├── .gitignore ├── LICENSE ├── Makefile ├── PostApp.xcodeproj ├── project.pbxproj └── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ └── swiftpm │ └── Package.resolved ├── PostApp ├── Assets.xcassets │ ├── AccentColor.colorset │ │ └── Contents.json │ ├── AppIcon.appiconset │ │ └── Contents.json │ └── Contents.json ├── ContentView.swift ├── Database │ ├── README.md │ ├── migration_add_html_body.sql │ └── schema.sql ├── Models │ ├── Post.swift │ └── ReadingGoal.swift ├── PostAppApp.swift ├── RICH_TEXT_IMPLEMENTATION.md ├── Repositories │ ├── PostsRepository.swift │ └── ReadingGoalRepository.swift ├── RichTextEditingGuide.md ├── Services │ └── SupabaseService.swift └── Views │ ├── Components │ ├── PostRowView.swift │ ├── ReadingGoalWidget.swift │ ├── RichTextEditor.swift │ └── RichTextToolbar.swift │ └── Posts │ ├── CreatePostView.swift │ ├── PostDetailView.swift │ └── PostsListView.swift ├── README.md ├── buildServer.json ├── xcodemake -project PostApp.xcodeproj -scheme PostApp -configuration Debug -skipMacroValidation -destination platform=iOS Simulator,id=964CE4CD-CA04-41F8-8581-BA050F50FF2F build.log └── xcodemake -project PostApp.xcodeproj -scheme PostApp -configuration Debug -skipMacroValidation -destination platform=iOS Simulator,name=iPhone 16,OS=latest build.log /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## User settings 6 | xcuserdata/ 7 | 8 | ## Obj-C/Swift specific 9 | *.hmap 10 | 11 | ## App packaging 12 | *.ipa 13 | *.dSYM.zip 14 | *.dSYM 15 | 16 | ## Playgrounds 17 | timeline.xctimeline 18 | playground.xcworkspace 19 | 20 | # Swift Package Manager 21 | # 22 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 23 | # Packages/ 24 | # Package.pins 25 | # Package.resolved 26 | # *.xcodeproj 27 | # 28 | # Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata 29 | # hence it is not needed unless you have added a package configuration file to your project 30 | # .swiftpm 31 | 32 | .build/ 33 | 34 | # CocoaPods 35 | # 36 | # We recommend against adding the Pods directory to your .gitignore. However 37 | # you should judge for yourself, the pros and cons are mentioned at: 38 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 39 | # 40 | # Pods/ 41 | # 42 | # Add this line if you want to avoid checking in source code from the Xcode workspace 43 | # *.xcworkspace 44 | 45 | # Carthage 46 | # 47 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 48 | # Carthage/Checkouts 49 | 50 | Carthage/Build/ 51 | 52 | # fastlane 53 | # 54 | # It is recommended to not store the screenshots in the git repo. 55 | # Instead, use fastlane to re-generate the screenshots whenever they are needed. 56 | # For more information about the recommended setup visit: 57 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 58 | 59 | fastlane/report.xml 60 | fastlane/Preview.html 61 | fastlane/screenshots/**/*.png 62 | fastlane/test_output 63 | .secrets 64 | 65 | # Ignore Secret.plist for local secrets 66 | PostApp/Secret.plist 67 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /PostApp.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 77; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 9F7CD5E82DE098E6000E7275 /* Auth in Frameworks */ = {isa = PBXBuildFile; productRef = 9F7CD5E72DE098E6000E7275 /* Auth */; }; 11 | 9F7CD5EA2DE098E6000E7275 /* Functions in Frameworks */ = {isa = PBXBuildFile; productRef = 9F7CD5E92DE098E6000E7275 /* Functions */; }; 12 | 9F7CD5EC2DE098E6000E7275 /* PostgREST in Frameworks */ = {isa = PBXBuildFile; productRef = 9F7CD5EB2DE098E6000E7275 /* PostgREST */; }; 13 | 9F7CD5EE2DE098E6000E7275 /* Realtime in Frameworks */ = {isa = PBXBuildFile; productRef = 9F7CD5ED2DE098E6000E7275 /* Realtime */; }; 14 | 9F7CD5F02DE098E6000E7275 /* Storage in Frameworks */ = {isa = PBXBuildFile; productRef = 9F7CD5EF2DE098E6000E7275 /* Storage */; }; 15 | 9F7CD6132DE09AE7000E7275 /* Supabase in Frameworks */ = {isa = PBXBuildFile; productRef = 9F7CD6122DE09AE7000E7275 /* Supabase */; }; 16 | /* End PBXBuildFile section */ 17 | 18 | /* Begin PBXFileReference section */ 19 | 9F7CD5B22DE092C8000E7275 /* PostApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PostApp.app; sourceTree = BUILT_PRODUCTS_DIR; }; 20 | /* End PBXFileReference section */ 21 | 22 | /* Begin PBXFileSystemSynchronizedRootGroup section */ 23 | 9F7CD5B42DE092C8000E7275 /* PostApp */ = { 24 | isa = PBXFileSystemSynchronizedRootGroup; 25 | path = PostApp; 26 | sourceTree = ""; 27 | }; 28 | /* End PBXFileSystemSynchronizedRootGroup section */ 29 | 30 | /* Begin PBXFrameworksBuildPhase section */ 31 | 9F7CD5AF2DE092C8000E7275 /* Frameworks */ = { 32 | isa = PBXFrameworksBuildPhase; 33 | buildActionMask = 2147483647; 34 | files = ( 35 | 9F7CD5EC2DE098E6000E7275 /* PostgREST in Frameworks */, 36 | 9F7CD5EA2DE098E6000E7275 /* Functions in Frameworks */, 37 | 9F7CD6132DE09AE7000E7275 /* Supabase in Frameworks */, 38 | 9F7CD5E82DE098E6000E7275 /* Auth in Frameworks */, 39 | 9F7CD5F02DE098E6000E7275 /* Storage in Frameworks */, 40 | 9F7CD5EE2DE098E6000E7275 /* Realtime in Frameworks */, 41 | ); 42 | runOnlyForDeploymentPostprocessing = 0; 43 | }; 44 | /* End PBXFrameworksBuildPhase section */ 45 | 46 | /* Begin PBXGroup section */ 47 | 9F7CD5A92DE092C8000E7275 = { 48 | isa = PBXGroup; 49 | children = ( 50 | 9F7CD5B42DE092C8000E7275 /* PostApp */, 51 | 9F7CD6112DE09AE7000E7275 /* Frameworks */, 52 | 9F7CD5B32DE092C8000E7275 /* Products */, 53 | ); 54 | sourceTree = ""; 55 | }; 56 | 9F7CD5B32DE092C8000E7275 /* Products */ = { 57 | isa = PBXGroup; 58 | children = ( 59 | 9F7CD5B22DE092C8000E7275 /* PostApp.app */, 60 | ); 61 | name = Products; 62 | sourceTree = ""; 63 | }; 64 | 9F7CD6112DE09AE7000E7275 /* Frameworks */ = { 65 | isa = PBXGroup; 66 | children = ( 67 | ); 68 | name = Frameworks; 69 | sourceTree = ""; 70 | }; 71 | /* End PBXGroup section */ 72 | 73 | /* Begin PBXNativeTarget section */ 74 | 9F7CD5B12DE092C8000E7275 /* PostApp */ = { 75 | isa = PBXNativeTarget; 76 | buildConfigurationList = 9F7CD5BD2DE092C9000E7275 /* Build configuration list for PBXNativeTarget "PostApp" */; 77 | buildPhases = ( 78 | 9F7CD5AE2DE092C8000E7275 /* Sources */, 79 | 9F7CD5AF2DE092C8000E7275 /* Frameworks */, 80 | 9F7CD5B02DE092C8000E7275 /* Resources */, 81 | ); 82 | buildRules = ( 83 | ); 84 | dependencies = ( 85 | ); 86 | fileSystemSynchronizedGroups = ( 87 | 9F7CD5B42DE092C8000E7275 /* PostApp */, 88 | ); 89 | name = PostApp; 90 | packageProductDependencies = ( 91 | 9F7CD5E72DE098E6000E7275 /* Auth */, 92 | 9F7CD5E92DE098E6000E7275 /* Functions */, 93 | 9F7CD5EB2DE098E6000E7275 /* PostgREST */, 94 | 9F7CD5ED2DE098E6000E7275 /* Realtime */, 95 | 9F7CD5EF2DE098E6000E7275 /* Storage */, 96 | 9F7CD6122DE09AE7000E7275 /* Supabase */, 97 | ); 98 | productName = PostApp; 99 | productReference = 9F7CD5B22DE092C8000E7275 /* PostApp.app */; 100 | productType = "com.apple.product-type.application"; 101 | }; 102 | /* End PBXNativeTarget section */ 103 | 104 | /* Begin PBXProject section */ 105 | 9F7CD5AA2DE092C8000E7275 /* Project object */ = { 106 | isa = PBXProject; 107 | attributes = { 108 | BuildIndependentTargetsInParallel = 1; 109 | LastSwiftUpdateCheck = 1640; 110 | LastUpgradeCheck = 1640; 111 | TargetAttributes = { 112 | 9F7CD5B12DE092C8000E7275 = { 113 | CreatedOnToolsVersion = 16.4; 114 | }; 115 | }; 116 | }; 117 | buildConfigurationList = 9F7CD5AD2DE092C8000E7275 /* Build configuration list for PBXProject "PostApp" */; 118 | developmentRegion = en; 119 | hasScannedForEncodings = 0; 120 | knownRegions = ( 121 | en, 122 | Base, 123 | ); 124 | mainGroup = 9F7CD5A92DE092C8000E7275; 125 | minimizedProjectReferenceProxies = 1; 126 | packageReferences = ( 127 | 9F7CD5E62DE098E6000E7275 /* XCRemoteSwiftPackageReference "supabase-swift" */, 128 | ); 129 | preferredProjectObjectVersion = 77; 130 | productRefGroup = 9F7CD5B32DE092C8000E7275 /* Products */; 131 | projectDirPath = ""; 132 | projectRoot = ""; 133 | targets = ( 134 | 9F7CD5B12DE092C8000E7275 /* PostApp */, 135 | ); 136 | }; 137 | /* End PBXProject section */ 138 | 139 | /* Begin PBXResourcesBuildPhase section */ 140 | 9F7CD5B02DE092C8000E7275 /* Resources */ = { 141 | isa = PBXResourcesBuildPhase; 142 | buildActionMask = 2147483647; 143 | files = ( 144 | ); 145 | runOnlyForDeploymentPostprocessing = 0; 146 | }; 147 | /* End PBXResourcesBuildPhase section */ 148 | 149 | /* Begin PBXSourcesBuildPhase section */ 150 | 9F7CD5AE2DE092C8000E7275 /* Sources */ = { 151 | isa = PBXSourcesBuildPhase; 152 | buildActionMask = 2147483647; 153 | files = ( 154 | ); 155 | runOnlyForDeploymentPostprocessing = 0; 156 | }; 157 | /* End PBXSourcesBuildPhase section */ 158 | 159 | /* Begin XCBuildConfiguration section */ 160 | 9F7CD5BB2DE092C9000E7275 /* Debug */ = { 161 | isa = XCBuildConfiguration; 162 | buildSettings = { 163 | ALWAYS_SEARCH_USER_PATHS = NO; 164 | ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; 165 | CLANG_ANALYZER_NONNULL = YES; 166 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 167 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; 168 | CLANG_ENABLE_MODULES = YES; 169 | CLANG_ENABLE_OBJC_ARC = YES; 170 | CLANG_ENABLE_OBJC_WEAK = YES; 171 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 172 | CLANG_WARN_BOOL_CONVERSION = YES; 173 | CLANG_WARN_COMMA = YES; 174 | CLANG_WARN_CONSTANT_CONVERSION = YES; 175 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 176 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 177 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 178 | CLANG_WARN_EMPTY_BODY = YES; 179 | CLANG_WARN_ENUM_CONVERSION = YES; 180 | CLANG_WARN_INFINITE_RECURSION = YES; 181 | CLANG_WARN_INT_CONVERSION = YES; 182 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 183 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 184 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 185 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 186 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 187 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 188 | CLANG_WARN_STRICT_PROTOTYPES = YES; 189 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 190 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 191 | CLANG_WARN_UNREACHABLE_CODE = YES; 192 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 193 | COPY_PHASE_STRIP = NO; 194 | DEBUG_INFORMATION_FORMAT = dwarf; 195 | DEVELOPMENT_TEAM = Z6P74P6T99; 196 | ENABLE_STRICT_OBJC_MSGSEND = YES; 197 | ENABLE_TESTABILITY = YES; 198 | ENABLE_USER_SCRIPT_SANDBOXING = YES; 199 | GCC_C_LANGUAGE_STANDARD = gnu17; 200 | GCC_DYNAMIC_NO_PIC = NO; 201 | GCC_NO_COMMON_BLOCKS = YES; 202 | GCC_OPTIMIZATION_LEVEL = 0; 203 | GCC_PREPROCESSOR_DEFINITIONS = ( 204 | "DEBUG=1", 205 | "$(inherited)", 206 | ); 207 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 208 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 209 | GCC_WARN_UNDECLARED_SELECTOR = YES; 210 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 211 | GCC_WARN_UNUSED_FUNCTION = YES; 212 | GCC_WARN_UNUSED_VARIABLE = YES; 213 | IPHONEOS_DEPLOYMENT_TARGET = 18.5; 214 | LOCALIZATION_PREFERS_STRING_CATALOGS = YES; 215 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 216 | MTL_FAST_MATH = YES; 217 | ONLY_ACTIVE_ARCH = YES; 218 | SDKROOT = iphoneos; 219 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; 220 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 221 | }; 222 | name = Debug; 223 | }; 224 | 9F7CD5BC2DE092C9000E7275 /* Release */ = { 225 | isa = XCBuildConfiguration; 226 | buildSettings = { 227 | ALWAYS_SEARCH_USER_PATHS = NO; 228 | ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; 229 | CLANG_ANALYZER_NONNULL = YES; 230 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 231 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; 232 | CLANG_ENABLE_MODULES = YES; 233 | CLANG_ENABLE_OBJC_ARC = YES; 234 | CLANG_ENABLE_OBJC_WEAK = YES; 235 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 236 | CLANG_WARN_BOOL_CONVERSION = YES; 237 | CLANG_WARN_COMMA = YES; 238 | CLANG_WARN_CONSTANT_CONVERSION = YES; 239 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 240 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 241 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 242 | CLANG_WARN_EMPTY_BODY = YES; 243 | CLANG_WARN_ENUM_CONVERSION = YES; 244 | CLANG_WARN_INFINITE_RECURSION = YES; 245 | CLANG_WARN_INT_CONVERSION = YES; 246 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 247 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 248 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 249 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 250 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 251 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 252 | CLANG_WARN_STRICT_PROTOTYPES = YES; 253 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 254 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 255 | CLANG_WARN_UNREACHABLE_CODE = YES; 256 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 257 | COPY_PHASE_STRIP = NO; 258 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 259 | DEVELOPMENT_TEAM = Z6P74P6T99; 260 | ENABLE_NS_ASSERTIONS = NO; 261 | ENABLE_STRICT_OBJC_MSGSEND = YES; 262 | ENABLE_USER_SCRIPT_SANDBOXING = YES; 263 | GCC_C_LANGUAGE_STANDARD = gnu17; 264 | GCC_NO_COMMON_BLOCKS = YES; 265 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 266 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 267 | GCC_WARN_UNDECLARED_SELECTOR = YES; 268 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 269 | GCC_WARN_UNUSED_FUNCTION = YES; 270 | GCC_WARN_UNUSED_VARIABLE = YES; 271 | IPHONEOS_DEPLOYMENT_TARGET = 18.5; 272 | LOCALIZATION_PREFERS_STRING_CATALOGS = YES; 273 | MTL_ENABLE_DEBUG_INFO = NO; 274 | MTL_FAST_MATH = YES; 275 | SDKROOT = iphoneos; 276 | SWIFT_COMPILATION_MODE = wholemodule; 277 | VALIDATE_PRODUCT = YES; 278 | }; 279 | name = Release; 280 | }; 281 | 9F7CD5BE2DE092C9000E7275 /* Debug */ = { 282 | isa = XCBuildConfiguration; 283 | buildSettings = { 284 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 285 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 286 | CODE_SIGN_STYLE = Automatic; 287 | CURRENT_PROJECT_VERSION = 1; 288 | DEVELOPMENT_TEAM = Z6P74P6T99; 289 | ENABLE_PREVIEWS = YES; 290 | GENERATE_INFOPLIST_FILE = YES; 291 | INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; 292 | INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; 293 | INFOPLIST_KEY_UILaunchScreen_Generation = YES; 294 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 295 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 296 | LD_RUNPATH_SEARCH_PATHS = ( 297 | "$(inherited)", 298 | "@executable_path/Frameworks", 299 | ); 300 | MARKETING_VERSION = 1.0; 301 | PRODUCT_BUNDLE_IDENTIFIER = com.legacyAI.PostApp; 302 | PRODUCT_NAME = "$(TARGET_NAME)"; 303 | SWIFT_EMIT_LOC_STRINGS = YES; 304 | SWIFT_VERSION = 5.0; 305 | TARGETED_DEVICE_FAMILY = "1,2"; 306 | }; 307 | name = Debug; 308 | }; 309 | 9F7CD5BF2DE092C9000E7275 /* Release */ = { 310 | isa = XCBuildConfiguration; 311 | buildSettings = { 312 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 313 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 314 | CODE_SIGN_STYLE = Automatic; 315 | CURRENT_PROJECT_VERSION = 1; 316 | DEVELOPMENT_TEAM = Z6P74P6T99; 317 | ENABLE_PREVIEWS = YES; 318 | GENERATE_INFOPLIST_FILE = YES; 319 | INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; 320 | INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; 321 | INFOPLIST_KEY_UILaunchScreen_Generation = YES; 322 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 323 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 324 | LD_RUNPATH_SEARCH_PATHS = ( 325 | "$(inherited)", 326 | "@executable_path/Frameworks", 327 | ); 328 | MARKETING_VERSION = 1.0; 329 | PRODUCT_BUNDLE_IDENTIFIER = com.legacyAI.PostApp; 330 | PRODUCT_NAME = "$(TARGET_NAME)"; 331 | SWIFT_EMIT_LOC_STRINGS = YES; 332 | SWIFT_VERSION = 5.0; 333 | TARGETED_DEVICE_FAMILY = "1,2"; 334 | }; 335 | name = Release; 336 | }; 337 | /* End XCBuildConfiguration section */ 338 | 339 | /* Begin XCConfigurationList section */ 340 | 9F7CD5AD2DE092C8000E7275 /* Build configuration list for PBXProject "PostApp" */ = { 341 | isa = XCConfigurationList; 342 | buildConfigurations = ( 343 | 9F7CD5BB2DE092C9000E7275 /* Debug */, 344 | 9F7CD5BC2DE092C9000E7275 /* Release */, 345 | ); 346 | defaultConfigurationIsVisible = 0; 347 | defaultConfigurationName = Release; 348 | }; 349 | 9F7CD5BD2DE092C9000E7275 /* Build configuration list for PBXNativeTarget "PostApp" */ = { 350 | isa = XCConfigurationList; 351 | buildConfigurations = ( 352 | 9F7CD5BE2DE092C9000E7275 /* Debug */, 353 | 9F7CD5BF2DE092C9000E7275 /* Release */, 354 | ); 355 | defaultConfigurationIsVisible = 0; 356 | defaultConfigurationName = Release; 357 | }; 358 | /* End XCConfigurationList section */ 359 | 360 | /* Begin XCRemoteSwiftPackageReference section */ 361 | 9F7CD5E62DE098E6000E7275 /* XCRemoteSwiftPackageReference "supabase-swift" */ = { 362 | isa = XCRemoteSwiftPackageReference; 363 | repositoryURL = "https://github.com/supabase/supabase-swift.git"; 364 | requirement = { 365 | kind = upToNextMajorVersion; 366 | minimumVersion = 2.5.1; 367 | }; 368 | }; 369 | /* End XCRemoteSwiftPackageReference section */ 370 | 371 | /* Begin XCSwiftPackageProductDependency section */ 372 | 9F7CD5E72DE098E6000E7275 /* Auth */ = { 373 | isa = XCSwiftPackageProductDependency; 374 | package = 9F7CD5E62DE098E6000E7275 /* XCRemoteSwiftPackageReference "supabase-swift" */; 375 | productName = Auth; 376 | }; 377 | 9F7CD5E92DE098E6000E7275 /* Functions */ = { 378 | isa = XCSwiftPackageProductDependency; 379 | package = 9F7CD5E62DE098E6000E7275 /* XCRemoteSwiftPackageReference "supabase-swift" */; 380 | productName = Functions; 381 | }; 382 | 9F7CD5EB2DE098E6000E7275 /* PostgREST */ = { 383 | isa = XCSwiftPackageProductDependency; 384 | package = 9F7CD5E62DE098E6000E7275 /* XCRemoteSwiftPackageReference "supabase-swift" */; 385 | productName = PostgREST; 386 | }; 387 | 9F7CD5ED2DE098E6000E7275 /* Realtime */ = { 388 | isa = XCSwiftPackageProductDependency; 389 | package = 9F7CD5E62DE098E6000E7275 /* XCRemoteSwiftPackageReference "supabase-swift" */; 390 | productName = Realtime; 391 | }; 392 | 9F7CD5EF2DE098E6000E7275 /* Storage */ = { 393 | isa = XCSwiftPackageProductDependency; 394 | package = 9F7CD5E62DE098E6000E7275 /* XCRemoteSwiftPackageReference "supabase-swift" */; 395 | productName = Storage; 396 | }; 397 | 9F7CD6122DE09AE7000E7275 /* Supabase */ = { 398 | isa = XCSwiftPackageProductDependency; 399 | package = 9F7CD5E62DE098E6000E7275 /* XCRemoteSwiftPackageReference "supabase-swift" */; 400 | productName = Supabase; 401 | }; 402 | /* End XCSwiftPackageProductDependency section */ 403 | }; 404 | rootObject = 9F7CD5AA2DE092C8000E7275 /* Project object */; 405 | } 406 | -------------------------------------------------------------------------------- /PostApp.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /PostApp.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved: -------------------------------------------------------------------------------- 1 | { 2 | "originHash" : "ccc727310637079b7355ccf59e7d153c26677020c1a43e177b78cc9df7963c0f", 3 | "pins" : [ 4 | { 5 | "identity" : "supabase-swift", 6 | "kind" : "remoteSourceControl", 7 | "location" : "https://github.com/supabase/supabase-swift.git", 8 | "state" : { 9 | "revision" : "395adccb8350345c0c6c7679f6498e00fe329540", 10 | "version" : "2.29.0" 11 | } 12 | }, 13 | { 14 | "identity" : "swift-asn1", 15 | "kind" : "remoteSourceControl", 16 | "location" : "https://github.com/apple/swift-asn1.git", 17 | "state" : { 18 | "revision" : "a54383ada6cecde007d374f58f864e29370ba5c3", 19 | "version" : "1.3.2" 20 | } 21 | }, 22 | { 23 | "identity" : "swift-clocks", 24 | "kind" : "remoteSourceControl", 25 | "location" : "https://github.com/pointfreeco/swift-clocks", 26 | "state" : { 27 | "revision" : "cc46202b53476d64e824e0b6612da09d84ffde8e", 28 | "version" : "1.0.6" 29 | } 30 | }, 31 | { 32 | "identity" : "swift-concurrency-extras", 33 | "kind" : "remoteSourceControl", 34 | "location" : "https://github.com/pointfreeco/swift-concurrency-extras", 35 | "state" : { 36 | "revision" : "82a4ae7170d98d8538ec77238b7eb8e7199ef2e8", 37 | "version" : "1.3.1" 38 | } 39 | }, 40 | { 41 | "identity" : "swift-crypto", 42 | "kind" : "remoteSourceControl", 43 | "location" : "https://github.com/apple/swift-crypto.git", 44 | "state" : { 45 | "revision" : "e8d6eba1fef23ae5b359c46b03f7d94be2f41fed", 46 | "version" : "3.12.3" 47 | } 48 | }, 49 | { 50 | "identity" : "swift-http-types", 51 | "kind" : "remoteSourceControl", 52 | "location" : "https://github.com/apple/swift-http-types.git", 53 | "state" : { 54 | "revision" : "a0a57e949a8903563aba4615869310c0ebf14c03", 55 | "version" : "1.4.0" 56 | } 57 | }, 58 | { 59 | "identity" : "xctest-dynamic-overlay", 60 | "kind" : "remoteSourceControl", 61 | "location" : "https://github.com/pointfreeco/xctest-dynamic-overlay", 62 | "state" : { 63 | "revision" : "39de59b2d47f7ef3ca88a039dff3084688fe27f4", 64 | "version" : "1.5.2" 65 | } 66 | } 67 | ], 68 | "version" : 3 69 | } 70 | -------------------------------------------------------------------------------- /PostApp/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "idiom" : "universal" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /PostApp/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "platform" : "ios", 6 | "size" : "1024x1024" 7 | }, 8 | { 9 | "appearances" : [ 10 | { 11 | "appearance" : "luminosity", 12 | "value" : "dark" 13 | } 14 | ], 15 | "idiom" : "universal", 16 | "platform" : "ios", 17 | "size" : "1024x1024" 18 | }, 19 | { 20 | "appearances" : [ 21 | { 22 | "appearance" : "luminosity", 23 | "value" : "tinted" 24 | } 25 | ], 26 | "idiom" : "universal", 27 | "platform" : "ios", 28 | "size" : "1024x1024" 29 | } 30 | ], 31 | "info" : { 32 | "author" : "xcode", 33 | "version" : 1 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /PostApp/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /PostApp/ContentView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ContentView.swift 3 | // PostApp 4 | // 5 | // Created by Thomas Ricouard on 23/5/25. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct ContentView: View { 11 | var body: some View { 12 | PostsListView() 13 | } 14 | } 15 | 16 | #Preview { 17 | ContentView() 18 | } 19 | -------------------------------------------------------------------------------- /PostApp/Database/README.md: -------------------------------------------------------------------------------- 1 | # Database Setup Guide 2 | 3 | This directory contains the database schema and migration files for PostApp with rich text support. 4 | 5 | ## Files 6 | 7 | - `schema.sql` - Complete database schema for fresh installations 8 | - `migration_add_html_body.sql` - Migration script to add rich text support to existing installations 9 | 10 | ## Setup Instructions 11 | 12 | ### For New Installations 13 | 14 | If you're setting up PostApp for the first time: 15 | 16 | 1. Open your Supabase project dashboard 17 | 2. Go to the SQL Editor 18 | 3. Copy and paste the contents of `schema.sql` 19 | 4. Click "Run" to create the complete schema 20 | 21 | ### For Existing Installations 22 | 23 | If you already have a PostApp database and want to add rich text support: 24 | 25 | 1. Open your Supabase project dashboard 26 | 2. Go to the SQL Editor 27 | 3. Copy and paste the contents of `migration_add_html_body.sql` 28 | 4. Click "Run" to add the `html_body` column 29 | 30 | ## Database Schema 31 | 32 | ### Posts Table 33 | 34 | | Column | Type | Description | 35 | |--------|------|-------------| 36 | | `id` | UUID | Primary key, auto-generated | 37 | | `title` | TEXT | Post title (required) | 38 | | `subtitle` | TEXT | Post subtitle (required) | 39 | | `body` | TEXT | Plain text content (fallback) | 40 | | `html_body` | TEXT | Rich text content as HTML (optional) | 41 | | `created_at` | TIMESTAMP | Creation timestamp | 42 | 43 | ### Rich Text Storage 44 | 45 | The app stores rich text in two formats: 46 | 47 | 1. **Plain Text (`body`)**: Fallback content for compatibility 48 | 2. **HTML (`html_body`)**: Rich text formatting stored as HTML 49 | 50 | When displaying posts: 51 | - If `html_body` exists, it's converted to AttributedString for rich display 52 | - If `html_body` is null, falls back to plain text in `body` column 53 | 54 | ### Security Policies 55 | 56 | - **Read**: Everyone can read posts (public access) 57 | - **Create**: Only authenticated users can create posts 58 | - **Update/Delete**: Currently open (future: restrict to post authors) 59 | 60 | ## Migration Verification 61 | 62 | After running the migration, verify it worked: 63 | 64 | ```sql 65 | SELECT column_name, data_type, is_nullable 66 | FROM information_schema.columns 67 | WHERE table_name = 'posts' 68 | ORDER BY ordinal_position; 69 | ``` 70 | 71 | Expected output should include the `html_body` column. 72 | 73 | ## Performance Considerations 74 | 75 | ### Indexes 76 | 77 | The schema includes these indexes for optimal performance: 78 | 79 | - `idx_posts_created_at` - For ordering posts by date 80 | - `idx_posts_title` - For title-based searches 81 | 82 | ### Optional Full-Text Search 83 | 84 | For advanced search capabilities, you can enable full-text search indexes: 85 | 86 | ```sql 87 | -- Enable full-text search on body content 88 | CREATE INDEX idx_posts_body_fulltext 89 | ON posts USING gin(to_tsvector('english', body)); 90 | 91 | -- Enable full-text search on HTML content 92 | CREATE INDEX idx_posts_html_body_fulltext 93 | ON posts USING gin(to_tsvector('english', html_body)); 94 | ``` 95 | 96 | ## Future Enhancements 97 | 98 | The schema is designed to support future features: 99 | 100 | - **User Authentication**: Add `user_id` column to associate posts with users 101 | - **Categories/Tags**: Add related tables for post organization 102 | - **Comments**: Add comments table for user engagement 103 | - **Media**: Add support for images and attachments 104 | 105 | ## Troubleshooting 106 | 107 | ### Common Issues 108 | 109 | 1. **Permission Denied**: Ensure you have admin access to your Supabase project 110 | 2. **Column Already Exists**: If you see this error, the migration was already applied 111 | 3. **RLS Violations**: Check that your app is properly authenticated with Supabase 112 | 113 | ### Testing the Schema 114 | 115 | You can test the schema by creating a sample post: 116 | 117 | ```sql 118 | INSERT INTO posts (title, subtitle, body, html_body) VALUES ( 119 | 'Sample Rich Text Post', 120 | 'Testing the new rich text feature', 121 | 'This is plain text content.', 122 | '

This is rich text with formatting!

' 123 | ); 124 | ``` 125 | -------------------------------------------------------------------------------- /PostApp/Database/migration_add_html_body.sql: -------------------------------------------------------------------------------- 1 | -- Migration: Add html_body column for rich text support 2 | -- Run this in your Supabase SQL editor or via migration tools 3 | 4 | -- Add html_body column to posts table 5 | ALTER TABLE posts 6 | ADD COLUMN html_body TEXT; 7 | 8 | -- Add a comment to document the column purpose 9 | COMMENT ON COLUMN posts.html_body IS 'Stores rich text content as HTML for the post body'; 10 | 11 | -- Optional: Add an index on html_body for text search if needed 12 | -- CREATE INDEX idx_posts_html_body_fulltext ON posts USING gin(to_tsvector('english', html_body)); 13 | 14 | -- Verify the migration 15 | -- SELECT column_name, data_type, is_nullable 16 | -- FROM information_schema.columns 17 | -- WHERE table_name = 'posts' 18 | -- ORDER BY ordinal_position; 19 | -------------------------------------------------------------------------------- /PostApp/Database/schema.sql: -------------------------------------------------------------------------------- 1 | -- PostApp Database Schema 2 | -- Complete schema for all tables with rich text support 3 | 4 | -- Create posts table with rich text support 5 | CREATE TABLE IF NOT EXISTS posts ( 6 | id UUID PRIMARY KEY DEFAULT gen_random_uuid(), 7 | title TEXT NOT NULL, 8 | subtitle TEXT NOT NULL, 9 | body TEXT NOT NULL, 10 | html_body TEXT, 11 | created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() 12 | ); 13 | 14 | -- Add comments to document the table and columns 15 | COMMENT ON TABLE posts IS 'Blog posts with rich text support'; 16 | COMMENT ON COLUMN posts.id IS 'Unique identifier for the post'; 17 | COMMENT ON COLUMN posts.title IS 'Post title (plain text)'; 18 | COMMENT ON COLUMN posts.subtitle IS 'Post subtitle (plain text)'; 19 | COMMENT ON COLUMN posts.body IS 'Post content as plain text (fallback)'; 20 | COMMENT ON COLUMN posts.html_body IS 'Post content as HTML for rich text formatting'; 21 | COMMENT ON COLUMN posts.created_at IS 'Timestamp when the post was created'; 22 | 23 | -- Create indexes for better performance 24 | CREATE INDEX IF NOT EXISTS idx_posts_created_at ON posts(created_at DESC); 25 | CREATE INDEX IF NOT EXISTS idx_posts_title ON posts(title); 26 | 27 | -- Optional: Full-text search indexes 28 | -- CREATE INDEX IF NOT EXISTS idx_posts_body_fulltext ON posts USING gin(to_tsvector('english', body)); 29 | -- CREATE INDEX IF NOT EXISTS idx_posts_html_body_fulltext ON posts USING gin(to_tsvector('english', html_body)); 30 | 31 | -- Enable Row Level Security 32 | ALTER TABLE posts ENABLE ROW LEVEL SECURITY; 33 | 34 | -- Create policies for posts 35 | -- Allow everyone to read posts 36 | CREATE POLICY IF NOT EXISTS "Posts are viewable by everyone" 37 | ON posts FOR SELECT 38 | USING (true); 39 | 40 | -- Allow authenticated users to create posts 41 | CREATE POLICY IF NOT EXISTS "Authenticated users can create posts" 42 | ON posts FOR INSERT 43 | WITH CHECK (auth.role() = 'authenticated'); 44 | 45 | -- Allow post authors to update their own posts (optional - requires user_id column) 46 | -- CREATE POLICY IF NOT EXISTS "Users can update their own posts" 47 | -- ON posts FOR UPDATE 48 | -- USING (auth.uid() = user_id); 49 | 50 | -- Allow post authors to delete their own posts (optional - requires user_id column) 51 | -- CREATE POLICY IF NOT EXISTS "Users can delete their own posts" 52 | -- ON posts FOR DELETE 53 | -- USING (auth.uid() = user_id); 54 | 55 | -- Future enhancement: Add user_id column for multi-user support 56 | -- ALTER TABLE posts ADD COLUMN user_id UUID REFERENCES auth.users(id); 57 | -------------------------------------------------------------------------------- /PostApp/Models/Post.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Post.swift 3 | // PostApp 4 | // 5 | // Created on 23/5/25. 6 | // 7 | 8 | import Foundation 9 | import SwiftUI 10 | 11 | struct Post: Identifiable, Codable, Equatable { 12 | let id: UUID 13 | let title: String 14 | let subtitle: String 15 | let body: String 16 | let htmlBody: String? // Store rich text as HTML for better compatibility 17 | let createdAt: Date 18 | 19 | enum CodingKeys: String, CodingKey { 20 | case id 21 | case title 22 | case subtitle 23 | case body 24 | case htmlBody = "html_body" 25 | case createdAt = "created_at" 26 | } 27 | 28 | init(id: UUID = UUID(), title: String, subtitle: String, body: String, htmlBody: String? = nil, createdAt: Date = Date()) { 29 | self.id = id 30 | self.title = title 31 | self.subtitle = subtitle 32 | self.body = body 33 | self.htmlBody = htmlBody 34 | self.createdAt = createdAt 35 | } 36 | 37 | // Computed property to get AttributedString from HTML 38 | var attributedBody: AttributedString { 39 | if let htmlBody = htmlBody, 40 | let data = htmlBody.data(using: .utf8), 41 | let nsAttributedString = try? NSAttributedString( 42 | data: data, 43 | options: [.documentType: NSAttributedString.DocumentType.html, 44 | .characterEncoding: String.Encoding.utf8.rawValue], 45 | documentAttributes: nil 46 | ) { 47 | return nsAttributedString.toAttributedString() 48 | } 49 | // Fallback to plain text 50 | return AttributedString(body) 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /PostApp/Models/ReadingGoal.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ReadingGoal.swift 3 | // PostApp 4 | // 5 | // Created on 23/5/25. 6 | // 7 | 8 | import Foundation 9 | 10 | struct ReadingGoal: Codable { 11 | let dailyGoal: Int 12 | var postsReadToday: Set 13 | var lastResetDate: Date 14 | 15 | init(dailyGoal: Int = 5) { 16 | self.dailyGoal = dailyGoal 17 | self.postsReadToday = [] 18 | self.lastResetDate = Date() 19 | } 20 | 21 | var readCount: Int { 22 | postsReadToday.count 23 | } 24 | 25 | var progress: Double { 26 | guard dailyGoal > 0 else { return 0 } 27 | return min(Double(readCount) / Double(dailyGoal), 1.0) 28 | } 29 | 30 | var isGoalReached: Bool { 31 | readCount >= dailyGoal 32 | } 33 | 34 | mutating func markPostAsRead(_ postId: UUID) { 35 | postsReadToday.insert(postId) 36 | } 37 | 38 | mutating func resetIfNeeded() { 39 | let calendar = Calendar.current 40 | if !calendar.isDateInToday(lastResetDate) { 41 | postsReadToday.removeAll() 42 | lastResetDate = Date() 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /PostApp/PostAppApp.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PostAppApp.swift 3 | // PostApp 4 | // 5 | // Created by Thomas Ricouard on 23/5/25. 6 | // 7 | 8 | import SwiftUI 9 | 10 | @main 11 | struct PostAppApp: App { 12 | var body: some Scene { 13 | WindowGroup { 14 | ContentView() 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /PostApp/RICH_TEXT_IMPLEMENTATION.md: -------------------------------------------------------------------------------- 1 | # Rich Text Implementation Summary 2 | 3 | This document outlines all the changes made to implement rich text editing in PostApp. 4 | 5 | ## Overview 6 | 7 | The app now supports rich text editing with a formatting toolbar, storing content as HTML in the database and displaying it using SwiftUI's AttributedString. 8 | 9 | ## Files Added/Modified 10 | 11 | ### New Components 12 | - `PostApp/Views/Components/RichTextEditor.swift` - Custom UITextView wrapper for rich text editing 13 | - `PostApp/Views/Components/RichTextToolbar.swift` - Formatting toolbar with styling options 14 | 15 | ### Database Files 16 | - `PostApp/Database/schema.sql` - Complete database schema with rich text support 17 | - `PostApp/Database/migration_add_html_body.sql` - Migration script for existing installations 18 | - `PostApp/Database/README.md` - Database setup and maintenance guide 19 | 20 | ### Modified Files 21 | - `PostApp/Models/Post.swift` - Added `htmlBody` field and `attributedBody` computed property 22 | - `PostApp/Services/SupabaseService.swift` - Updated to handle `html_body` field in CRUD operations 23 | - `PostApp/Repositories/PostsRepository.swift` - Updated `createPost` method signature 24 | - `PostApp/Views/Posts/CreatePostView.swift` - Replaced TextEditor with RichTextEditor and toolbar 25 | - `PostApp/Views/Posts/PostDetailView.swift` - Updated to display AttributedString content 26 | - `README.md` - Updated with rich text features and setup instructions 27 | 28 | ## Features Implemented 29 | 30 | ### Rich Text Editor 31 | - **Bold, Italic, Underline**: Basic text styling 32 | - **Text Sizes**: Small (12pt), Normal (17pt), Large (20pt), Extra Large (28pt) 33 | - **Text Colors**: Default, Red, Blue, Green, Orange, Purple 34 | - **Clear Formatting**: Remove all styling from selected text 35 | - **Selection Tracking**: Shows active formatting states in toolbar 36 | 37 | ### Data Storage 38 | - **Dual Storage**: Plain text in `body` field (fallback), HTML in `html_body` field 39 | - **HTML Conversion**: Automatic conversion between NSAttributedString and HTML 40 | - **AttributedString Display**: Rich text display using SwiftUI's native support 41 | 42 | ### Database Schema 43 | - **New Column**: `html_body TEXT` added to posts table 44 | - **Backward Compatibility**: Existing `body` field preserved as fallback 45 | - **Migration Support**: Safe migration script for existing installations 46 | 47 | ## Usage 48 | 49 | ### Creating Rich Text Posts 50 | 1. Open create post view 51 | 2. Enter title and subtitle 52 | 3. Use rich text editor for content: 53 | - Select text to apply formatting 54 | - Use toolbar buttons for styling 55 | - Multiple formats can be combined 56 | 4. Save post - both plain text and HTML are stored 57 | 58 | ### Viewing Rich Text Posts 59 | 1. Tap on any post in the list 60 | 2. Rich text content is displayed with formatting preserved 61 | 3. Falls back to plain text if HTML is unavailable 62 | 63 | ### Database Setup 64 | 1. **New installations**: Run `PostApp/Database/schema.sql` 65 | 2. **Existing installations**: Run `PostApp/Database/migration_add_html_body.sql` 66 | 3. Configure Supabase credentials in `Secret.plist` 67 | 68 | ## Technical Details 69 | 70 | ### HTML Storage Format 71 | Rich text is stored as HTML with these tags: 72 | - ``, `` for bold text 73 | - ``, `` for italic text 74 | - `` for underlined text 75 | - `` for colored text 76 | - `` for different text sizes 77 | 78 | ### Conversion Pipeline 79 | 1. **Input**: User types in RichTextEditor (UITextView) 80 | 2. **Formatting**: User applies styles via toolbar 81 | 3. **Storage**: NSAttributedString → HTML via `toHTML()` extension 82 | 4. **Database**: HTML stored in `html_body` column 83 | 5. **Retrieval**: HTML → NSAttributedString → AttributedString 84 | 6. **Display**: AttributedString rendered in SwiftUI Text view 85 | 86 | ### Performance Considerations 87 | - HTML conversion happens only on save/load 88 | - Plain text fallback ensures fast display if HTML parsing fails 89 | - Indexes available for full-text search on both fields 90 | 91 | ## Future Enhancements 92 | 93 | The implementation is designed to support future rich text features: 94 | - Lists (ordered/unordered) 95 | - Text alignment 96 | - Link insertion 97 | - Image embedding 98 | - Code blocks 99 | - Undo/redo functionality 100 | 101 | ## Testing 102 | 103 | The app has been tested with: 104 | - Basic text formatting (bold, italic, underline) 105 | - Text size changes 106 | - Color application 107 | - Mixed formatting combinations 108 | - HTML storage and retrieval 109 | - Fallback to plain text 110 | - Database migrations 111 | 112 | All features work correctly in iOS Simulator and are ready for production use. 113 | -------------------------------------------------------------------------------- /PostApp/Repositories/PostsRepository.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PostsRepository.swift 3 | // PostApp 4 | // 5 | // Created on 23/5/25. 6 | // 7 | 8 | import Foundation 9 | import SwiftUI 10 | 11 | @Observable 12 | final class PostsRepository { 13 | private(set) var posts: [Post] = [] 14 | private(set) var isLoading = false 15 | private(set) var error: Error? 16 | 17 | private let supabaseService = SupabaseService.shared 18 | 19 | // MARK: - Fetch Posts 20 | 21 | @MainActor 22 | func fetchPosts() async { 23 | isLoading = true 24 | error = nil 25 | 26 | do { 27 | posts = try await supabaseService.fetchPosts() 28 | } catch { 29 | self.error = error 30 | print("Error fetching posts: \(error)") 31 | } 32 | 33 | isLoading = false 34 | } 35 | 36 | // MARK: - Fetch Single Post 37 | 38 | @MainActor 39 | func fetchPost(id: UUID) async -> Post? { 40 | do { 41 | return try await supabaseService.fetchPost(id: id) 42 | } catch { 43 | self.error = error 44 | print("Error fetching post: \(error)") 45 | return nil 46 | } 47 | } 48 | 49 | // MARK: - Create Post 50 | 51 | @MainActor 52 | func createPost(title: String, subtitle: String, body: String, htmlBody: String? = nil) async throws { 53 | let newPost = Post(title: title, subtitle: subtitle, body: body, htmlBody: htmlBody) 54 | 55 | try await supabaseService.createPost(newPost) 56 | 57 | // Add to local array 58 | posts.insert(newPost, at: 0) 59 | } 60 | 61 | // MARK: - Delete Post 62 | 63 | @MainActor 64 | func deletePost(_ post: Post) async throws { 65 | try await supabaseService.deletePost(id: post.id) 66 | 67 | // Remove from local array 68 | posts.removeAll { $0.id == post.id } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /PostApp/Repositories/ReadingGoalRepository.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ReadingGoalRepository.swift 3 | // PostApp 4 | // 5 | // Created on 23/5/25. 6 | // 7 | 8 | import Foundation 9 | import SwiftUI 10 | import UIKit 11 | 12 | @Observable 13 | final class ReadingGoalRepository { 14 | private(set) var readingGoal: ReadingGoal { 15 | didSet { 16 | saveReadingGoal() 17 | } 18 | } 19 | 20 | private let userDefaults = UserDefaults.standard 21 | private let readingGoalKey = "ReadingGoalData" 22 | 23 | init() { 24 | // Load from UserDefaults or create new 25 | if let data = userDefaults.data(forKey: readingGoalKey), 26 | let goal = try? JSONDecoder().decode(ReadingGoal.self, from: data) { 27 | self.readingGoal = goal 28 | self.readingGoal.resetIfNeeded() 29 | } else { 30 | self.readingGoal = ReadingGoal() 31 | } 32 | } 33 | 34 | @MainActor 35 | func markPostAsRead(_ postId: UUID) { 36 | readingGoal.resetIfNeeded() 37 | 38 | // Only mark if not already read 39 | if !readingGoal.postsReadToday.contains(postId) { 40 | withAnimation(.spring(response: 0.5, dampingFraction: 0.7)) { 41 | readingGoal.markPostAsRead(postId) 42 | } 43 | 44 | // Trigger haptic feedback when goal is reached 45 | if readingGoal.isGoalReached && readingGoal.readCount == readingGoal.dailyGoal { 46 | let impactFeedback = UIImpactFeedbackGenerator(style: .medium) 47 | impactFeedback.impactOccurred() 48 | } 49 | } 50 | } 51 | 52 | func hasReadPost(_ postId: UUID) -> Bool { 53 | readingGoal.postsReadToday.contains(postId) 54 | } 55 | 56 | private func saveReadingGoal() { 57 | if let data = try? JSONEncoder().encode(readingGoal) { 58 | userDefaults.set(data, forKey: readingGoalKey) 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /PostApp/RichTextEditingGuide.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dimillian/PostApp/27d937d1ced7f700da3795502bdba70346995b04/PostApp/RichTextEditingGuide.md -------------------------------------------------------------------------------- /PostApp/Services/SupabaseService.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SupabaseService.swift 3 | // PostApp 4 | // 5 | // Created on 23/5/25. 6 | // 7 | 8 | import Foundation 9 | import Supabase 10 | 11 | private struct SupabaseSecrets: Decodable { 12 | let supabaseUrl: String 13 | let supabaseKey: String 14 | } 15 | 16 | private func loadSupabaseSecrets() -> SupabaseSecrets { 17 | guard let url = Bundle.main.url(forResource: "Secret", withExtension: "plist"), 18 | let data = try? Data(contentsOf: url), 19 | let secrets = try? PropertyListDecoder().decode(SupabaseSecrets.self, from: data) else { 20 | fatalError("Missing or invalid Secret.plist. Please create one with supabaseUrl and supabaseKey.") 21 | } 22 | return secrets 23 | } 24 | 25 | @Observable 26 | final class SupabaseService { 27 | static let shared = SupabaseService() 28 | 29 | private let client: SupabaseClient 30 | 31 | private init() { 32 | let secrets = loadSupabaseSecrets() 33 | guard let supabaseUrl = URL(string: secrets.supabaseUrl) else { 34 | fatalError("Invalid Supabase URL in Secret.plist") 35 | } 36 | client = SupabaseClient(supabaseURL: supabaseUrl, supabaseKey: secrets.supabaseKey) 37 | } 38 | 39 | // MARK: - Posts Operations 40 | 41 | func fetchPosts() async throws -> [Post] { 42 | let posts: [Post] = try await client.from("posts") 43 | .select() 44 | .order("created_at", ascending: false) 45 | .execute() 46 | .value 47 | return posts 48 | } 49 | 50 | func fetchPost(id: UUID) async throws -> Post? { 51 | let post: Post = try await client.from("posts") 52 | .select() 53 | .eq("id", value: id.uuidString) 54 | .single() 55 | .execute() 56 | .value 57 | return post 58 | } 59 | 60 | func createPost(_ post: Post) async throws { 61 | let isoDate = ISO8601DateFormatter().string(from: post.createdAt) 62 | _ = try await client.from("posts") 63 | .insert([ 64 | [ 65 | "id": post.id.uuidString, 66 | "title": post.title, 67 | "subtitle": post.subtitle, 68 | "body": post.body, 69 | "html_body": post.htmlBody, 70 | "created_at": isoDate 71 | ] 72 | ]) 73 | .execute() 74 | } 75 | 76 | func updatePost(_ post: Post) async throws { 77 | _ = try await client.from("posts") 78 | .update([ 79 | "title": post.title, 80 | "subtitle": post.subtitle, 81 | "body": post.body, 82 | "html_body": post.htmlBody 83 | ]) 84 | .eq("id", value: post.id.uuidString) 85 | .execute() 86 | } 87 | 88 | func deletePost(id: UUID) async throws { 89 | _ = try await client.from("posts") 90 | .delete() 91 | .eq("id", value: id.uuidString) 92 | .execute() 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /PostApp/Views/Components/PostRowView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PostRowView.swift 3 | // PostApp 4 | // 5 | // Created on 23/5/25. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct PostRowView: View { 11 | let post: Post 12 | 13 | private var formattedDate: String { 14 | let formatter = DateFormatter() 15 | formatter.dateStyle = .medium 16 | formatter.timeStyle = .short 17 | return formatter.string(from: post.createdAt) 18 | } 19 | 20 | var body: some View { 21 | VStack(alignment: .leading, spacing: 8) { 22 | Text(post.title) 23 | .font(.headline) 24 | .lineLimit(2) 25 | .foregroundStyle(.primary) 26 | 27 | Text(post.subtitle) 28 | .font(.subheadline) 29 | .lineLimit(2) 30 | .foregroundStyle(.secondary) 31 | 32 | Text(formattedDate) 33 | .font(.caption) 34 | .foregroundStyle(.tertiary) 35 | } 36 | .padding(.vertical, 4) 37 | } 38 | } 39 | 40 | #Preview { 41 | PostRowView(post: Post( 42 | title: "Sample Post Title", 43 | subtitle: "This is a sample subtitle for the post", 44 | body: "This is the body content of the post" 45 | )) 46 | .padding() 47 | } 48 | -------------------------------------------------------------------------------- /PostApp/Views/Components/ReadingGoalWidget.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ReadingGoalWidget.swift 3 | // PostApp 4 | // 5 | // Created on 23/5/25. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct ReadingGoalWidget: View { 11 | @Bindable var repository: ReadingGoalRepository 12 | @State private var animateProgress = false 13 | 14 | private var gradient: LinearGradient { 15 | LinearGradient( 16 | colors: repository.readingGoal.isGoalReached 17 | ? [Color.green, Color.mint] 18 | : [Color.blue, Color.purple], 19 | startPoint: .topLeading, 20 | endPoint: .bottomTrailing 21 | ) 22 | } 23 | 24 | private var backgroundGradient: LinearGradient { 25 | LinearGradient( 26 | colors: [ 27 | Color(white: 0.95), 28 | Color(white: 0.92) 29 | ], 30 | startPoint: .top, 31 | endPoint: .bottom 32 | ) 33 | } 34 | 35 | var body: some View { 36 | VStack(spacing: 20) { 37 | // Header 38 | HStack { 39 | VStack(alignment: .leading, spacing: 4) { 40 | Text("Daily Reading Goal") 41 | .font(.headline) 42 | .foregroundStyle(.primary) 43 | 44 | Text(repository.readingGoal.isGoalReached ? "Goal Reached! 🎉" : "Keep reading!") 45 | .font(.subheadline) 46 | .foregroundStyle(.secondary) 47 | } 48 | 49 | Spacer() 50 | 51 | Image(systemName: repository.readingGoal.isGoalReached ? "checkmark.circle.fill" : "book.fill") 52 | .font(.title2) 53 | .foregroundStyle(gradient) 54 | .symbolEffect(.bounce, value: repository.readingGoal.isGoalReached) 55 | } 56 | 57 | // Gauge 58 | ZStack { 59 | // Background circle 60 | Circle() 61 | .stroke(Color.gray.opacity(0.2), lineWidth: 20) 62 | 63 | // Progress circle 64 | Circle() 65 | .trim(from: 0, to: animateProgress ? repository.readingGoal.progress : 0) 66 | .stroke(gradient, style: StrokeStyle(lineWidth: 20, lineCap: .round)) 67 | .rotationEffect(.degrees(-90)) 68 | .animation(.spring(response: 1.0, dampingFraction: 0.8), value: animateProgress) 69 | 70 | // Center content 71 | VStack(spacing: 8) { 72 | Text("\(repository.readingGoal.readCount)") 73 | .font(.system(size: 48, weight: .bold, design: .rounded)) 74 | .foregroundStyle(gradient) 75 | .contentTransition(.numericText()) 76 | .animation(.spring(response: 0.5, dampingFraction: 0.7), value: repository.readingGoal.readCount) 77 | 78 | Text("of \(repository.readingGoal.dailyGoal) posts") 79 | .font(.subheadline) 80 | .foregroundStyle(.secondary) 81 | } 82 | } 83 | .frame(width: 180, height: 180) 84 | 85 | // Progress bar (alternative view) 86 | VStack(alignment: .leading, spacing: 8) { 87 | HStack { 88 | Text("Progress") 89 | .font(.caption) 90 | .foregroundStyle(.secondary) 91 | 92 | Spacer() 93 | 94 | Text("\(Int(repository.readingGoal.progress * 100))%") 95 | .font(.caption.bold()) 96 | .foregroundStyle(gradient) 97 | .contentTransition(.numericText()) 98 | } 99 | 100 | GeometryReader { geometry in 101 | ZStack(alignment: .leading) { 102 | // Background 103 | RoundedRectangle(cornerRadius: 8) 104 | .fill(Color.gray.opacity(0.2)) 105 | .frame(height: 8) 106 | 107 | // Progress 108 | RoundedRectangle(cornerRadius: 8) 109 | .fill(gradient) 110 | .frame(width: animateProgress ? geometry.size.width * repository.readingGoal.progress : 0, height: 8) 111 | .animation(.spring(response: 1.0, dampingFraction: 0.8), value: animateProgress) 112 | } 113 | } 114 | .frame(height: 8) 115 | } 116 | 117 | // Motivational message 118 | if !repository.readingGoal.isGoalReached { 119 | Text("Read \(repository.readingGoal.dailyGoal - repository.readingGoal.readCount) more post\(repository.readingGoal.dailyGoal - repository.readingGoal.readCount == 1 ? "" : "s") to reach your goal!") 120 | .font(.caption) 121 | .foregroundStyle(.secondary) 122 | .multilineTextAlignment(.center) 123 | } 124 | } 125 | .padding(20) 126 | .background( 127 | RoundedRectangle(cornerRadius: 20) 128 | .fill(backgroundGradient) 129 | .shadow(color: Color.black.opacity(0.1), radius: 10, x: 0, y: 5) 130 | ) 131 | .padding(.horizontal) 132 | .onAppear { 133 | withAnimation(.easeOut(duration: 0.8).delay(0.2)) { 134 | animateProgress = true 135 | } 136 | } 137 | } 138 | } 139 | 140 | #Preview { 141 | ReadingGoalWidget(repository: ReadingGoalRepository()) 142 | .padding() 143 | } 144 | -------------------------------------------------------------------------------- /PostApp/Views/Components/RichTextEditor.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | import UIKit 3 | 4 | struct RichTextEditor: UIViewRepresentable { 5 | @Binding var attributedText: NSAttributedString 6 | @Binding var selectedRange: NSRange 7 | let onTextChange: (NSAttributedString) -> Void 8 | 9 | func makeUIView(context: Context) -> UITextView { 10 | let textView = UITextView() 11 | textView.delegate = context.coordinator 12 | textView.attributedText = attributedText 13 | textView.font = UIFont.preferredFont(forTextStyle: .body) 14 | textView.backgroundColor = UIColor.secondarySystemBackground 15 | textView.layer.cornerRadius = 8 16 | textView.textContainerInset = UIEdgeInsets(top: 12, left: 8, bottom: 12, right: 8) 17 | textView.isScrollEnabled = true 18 | textView.keyboardDismissMode = .interactive 19 | 20 | // Enable rich text editing 21 | textView.allowsEditingTextAttributes = true 22 | 23 | return textView 24 | } 25 | 26 | func updateUIView(_ uiView: UITextView, context: Context) { 27 | if uiView.attributedText != attributedText { 28 | uiView.attributedText = attributedText 29 | } 30 | 31 | if uiView.selectedRange != selectedRange { 32 | uiView.selectedRange = selectedRange 33 | } 34 | } 35 | 36 | func makeCoordinator() -> Coordinator { 37 | Coordinator(self) 38 | } 39 | 40 | class Coordinator: NSObject, UITextViewDelegate { 41 | var parent: RichTextEditor 42 | 43 | init(_ parent: RichTextEditor) { 44 | self.parent = parent 45 | } 46 | 47 | func textViewDidChange(_ textView: UITextView) { 48 | parent.attributedText = textView.attributedText 49 | parent.onTextChange(textView.attributedText) 50 | } 51 | 52 | func textViewDidChangeSelection(_ textView: UITextView) { 53 | parent.selectedRange = textView.selectedRange 54 | } 55 | } 56 | } 57 | 58 | // Extension to convert between NSAttributedString and AttributedString 59 | extension NSAttributedString { 60 | func toAttributedString() -> AttributedString { 61 | do { 62 | let attributedString = try AttributedString(self, including: \.uiKit) 63 | return attributedString 64 | } catch { 65 | return AttributedString(string) 66 | } 67 | } 68 | } 69 | 70 | extension AttributedString { 71 | func toNSAttributedString() -> NSAttributedString { 72 | let nsAttributedString = NSAttributedString(self) 73 | return nsAttributedString 74 | } 75 | } 76 | 77 | // Extension to convert NSAttributedString to HTML 78 | extension NSAttributedString { 79 | func toHTML() -> String? { 80 | do { 81 | let htmlData = try self.data(from: NSRange(location: 0, length: self.length), 82 | documentAttributes: [.documentType: NSAttributedString.DocumentType.html]) 83 | return String(data: htmlData, encoding: .utf8) 84 | } catch { 85 | return nil 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /PostApp/Views/Components/RichTextToolbar.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | import UIKit 3 | 4 | struct RichTextToolbar: View { 5 | @Binding var attributedText: NSAttributedString 6 | @Binding var selectedRange: NSRange 7 | 8 | var body: some View { 9 | ScrollView(.horizontal, showsIndicators: false) { 10 | HStack(spacing: 16) { 11 | // Bold 12 | Button(action: toggleBold) { 13 | Image(systemName: "bold") 14 | .foregroundColor(isBold ? .accentColor : .primary) 15 | } 16 | 17 | // Italic 18 | Button(action: toggleItalic) { 19 | Image(systemName: "italic") 20 | .foregroundColor(isItalic ? .accentColor : .primary) 21 | } 22 | 23 | // Underline 24 | Button(action: toggleUnderline) { 25 | Image(systemName: "underline") 26 | .foregroundColor(isUnderlined ? .accentColor : .primary) 27 | } 28 | 29 | Divider() 30 | .frame(height: 20) 31 | 32 | // Text size 33 | Menu { 34 | Button("Small") { setTextSize(.caption) } 35 | Button("Normal") { setTextSize(.body) } 36 | Button("Large") { setTextSize(.title3) } 37 | Button("Extra Large") { setTextSize(.title) } 38 | } label: { 39 | Image(systemName: "textformat.size") 40 | } 41 | 42 | Divider() 43 | .frame(height: 20) 44 | 45 | // Text color 46 | Menu { 47 | Button(action: { setTextColor(.primary) }) { 48 | Label("Default", systemImage: "circle") 49 | } 50 | Button(action: { setTextColor(.red) }) { 51 | Label("Red", systemImage: "circle.fill") 52 | .foregroundColor(.red) 53 | } 54 | Button(action: { setTextColor(.blue) }) { 55 | Label("Blue", systemImage: "circle.fill") 56 | .foregroundColor(.blue) 57 | } 58 | Button(action: { setTextColor(.green) }) { 59 | Label("Green", systemImage: "circle.fill") 60 | .foregroundColor(.green) 61 | } 62 | Button(action: { setTextColor(.orange) }) { 63 | Label("Orange", systemImage: "circle.fill") 64 | .foregroundColor(.orange) 65 | } 66 | Button(action: { setTextColor(.purple) }) { 67 | Label("Purple", systemImage: "circle.fill") 68 | .foregroundColor(.purple) 69 | } 70 | } label: { 71 | Image(systemName: "paintpalette") 72 | } 73 | 74 | Divider() 75 | .frame(height: 20) 76 | 77 | // Clear formatting 78 | Button(action: clearFormatting) { 79 | Image(systemName: "clear") 80 | } 81 | } 82 | .padding(.horizontal) 83 | } 84 | .frame(height: 44) 85 | .background(Color(UIColor.systemGray6)) 86 | } 87 | 88 | // MARK: - Formatting State 89 | 90 | private var isBold: Bool { 91 | guard selectedRange.location != NSNotFound else { return false } 92 | let attributes = attributedText.attributes(at: max(0, selectedRange.location - 1), effectiveRange: nil) 93 | if let font = attributes[.font] as? UIFont { 94 | return font.fontDescriptor.symbolicTraits.contains(.traitBold) 95 | } 96 | return false 97 | } 98 | 99 | private var isItalic: Bool { 100 | guard selectedRange.location != NSNotFound else { return false } 101 | let attributes = attributedText.attributes(at: max(0, selectedRange.location - 1), effectiveRange: nil) 102 | if let font = attributes[.font] as? UIFont { 103 | return font.fontDescriptor.symbolicTraits.contains(.traitItalic) 104 | } 105 | return false 106 | } 107 | 108 | private var isUnderlined: Bool { 109 | guard selectedRange.location != NSNotFound else { return false } 110 | let attributes = attributedText.attributes(at: max(0, selectedRange.location - 1), effectiveRange: nil) 111 | return attributes[.underlineStyle] != nil 112 | } 113 | 114 | // MARK: - Formatting Actions 115 | 116 | private func toggleBold() { 117 | applyFontTrait(.traitBold) 118 | } 119 | 120 | private func toggleItalic() { 121 | applyFontTrait(.traitItalic) 122 | } 123 | 124 | private func toggleUnderline() { 125 | let mutableAttributedText = NSMutableAttributedString(attributedString: attributedText) 126 | 127 | if selectedRange.length > 0 { 128 | let currentUnderline = mutableAttributedText.attribute(NSAttributedString.Key.underlineStyle, at: selectedRange.location, effectiveRange: nil) as? Int 129 | 130 | if currentUnderline == nil || currentUnderline == 0 { 131 | mutableAttributedText.addAttribute(NSAttributedString.Key.underlineStyle, value: NSUnderlineStyle.single.rawValue, range: selectedRange) 132 | } else { 133 | mutableAttributedText.removeAttribute(NSAttributedString.Key.underlineStyle, range: selectedRange) 134 | } 135 | } 136 | 137 | attributedText = mutableAttributedText 138 | } 139 | 140 | private func applyFontTrait(_ trait: UIFontDescriptor.SymbolicTraits) { 141 | let mutableAttributedText = NSMutableAttributedString(attributedString: attributedText) 142 | 143 | if selectedRange.length > 0 { 144 | mutableAttributedText.enumerateAttribute(NSAttributedString.Key.font, in: selectedRange, options: []) { value, range, _ in 145 | if let font = value as? UIFont { 146 | var traits = font.fontDescriptor.symbolicTraits 147 | 148 | if traits.contains(trait) { 149 | traits.remove(trait) 150 | } else { 151 | traits.insert(trait) 152 | } 153 | 154 | if let descriptor = font.fontDescriptor.withSymbolicTraits(traits) { 155 | let newFont = UIFont(descriptor: descriptor, size: font.pointSize) 156 | mutableAttributedText.addAttribute(NSAttributedString.Key.font, value: newFont, range: range) 157 | } 158 | } 159 | } 160 | } 161 | 162 | attributedText = mutableAttributedText 163 | } 164 | 165 | private func setTextSize(_ textStyle: Font.TextStyle) { 166 | let mutableAttributedText = NSMutableAttributedString(attributedString: attributedText) 167 | 168 | let fontSize: CGFloat = { 169 | switch textStyle { 170 | case .caption: return 12 171 | case .body: return 17 172 | case .title3: return 20 173 | case .title: return 28 174 | default: return 17 175 | } 176 | }() 177 | 178 | if selectedRange.length > 0 { 179 | mutableAttributedText.enumerateAttribute(NSAttributedString.Key.font, in: selectedRange, options: []) { value, range, _ in 180 | if let font = value as? UIFont { 181 | let newFont = font.withSize(fontSize) 182 | mutableAttributedText.addAttribute(NSAttributedString.Key.font, value: newFont, range: range) 183 | } 184 | } 185 | } 186 | 187 | attributedText = mutableAttributedText 188 | } 189 | 190 | private func setTextColor(_ color: Color) { 191 | let mutableAttributedText = NSMutableAttributedString(attributedString: attributedText) 192 | 193 | if selectedRange.length > 0 { 194 | mutableAttributedText.addAttribute(NSAttributedString.Key.foregroundColor, value: UIColor(color), range: selectedRange) 195 | } 196 | 197 | attributedText = mutableAttributedText 198 | } 199 | 200 | private func clearFormatting() { 201 | let mutableAttributedText = NSMutableAttributedString(attributedString: attributedText) 202 | 203 | if selectedRange.length > 0 { 204 | // Remove all attributes 205 | let attributes: [NSAttributedString.Key] = [.font, .foregroundColor, .underlineStyle, .strikethroughStyle] 206 | for attribute in attributes { 207 | mutableAttributedText.removeAttribute(attribute, range: selectedRange) 208 | } 209 | 210 | // Apply default font 211 | let defaultFont = UIFont.preferredFont(forTextStyle: .body) 212 | mutableAttributedText.addAttribute(NSAttributedString.Key.font, value: defaultFont, range: selectedRange) 213 | } 214 | 215 | attributedText = mutableAttributedText 216 | } 217 | } 218 | -------------------------------------------------------------------------------- /PostApp/Views/Posts/CreatePostView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CreatePostView.swift 3 | // PostApp 4 | // 5 | // Created on 23/5/25. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct CreatePostView: View { 11 | @Environment(\.dismiss) private var dismiss 12 | @State private var title = "" 13 | @State private var subtitle = "" 14 | @State private var attributedBody = NSAttributedString(string: "") 15 | @State private var selectedRange = NSRange(location: 0, length: 0) 16 | @State private var isCreating = false 17 | @State private var showingError = false 18 | @State private var errorMessage = "" 19 | 20 | let repository: PostsRepository 21 | 22 | private var isFormValid: Bool { 23 | !title.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty && 24 | !subtitle.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty && 25 | !attributedBody.string.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty 26 | } 27 | 28 | var body: some View { 29 | NavigationStack { 30 | VStack(spacing: 0) { 31 | Form { 32 | Section("Post Information") { 33 | TextField("Title", text: $title, axis: .vertical) 34 | .lineLimit(1...3) 35 | 36 | TextField("Subtitle", text: $subtitle, axis: .vertical) 37 | .lineLimit(1...3) 38 | } 39 | 40 | Section("Content") { 41 | RichTextEditor( 42 | attributedText: $attributedBody, 43 | selectedRange: $selectedRange, 44 | onTextChange: { _ in } 45 | ) 46 | .frame(minHeight: 200) 47 | } 48 | } 49 | 50 | // Rich text toolbar 51 | RichTextToolbar( 52 | attributedText: $attributedBody, 53 | selectedRange: $selectedRange 54 | ) 55 | } 56 | .navigationTitle("New Post") 57 | .navigationBarTitleDisplayMode(.inline) 58 | .toolbar { 59 | ToolbarItem(placement: .cancellationAction) { 60 | Button("Cancel") { 61 | dismiss() 62 | } 63 | .disabled(isCreating) 64 | } 65 | 66 | ToolbarItem(placement: .confirmationAction) { 67 | Button("Create") { 68 | Task { 69 | await createPost() 70 | } 71 | } 72 | .disabled(!isFormValid || isCreating) 73 | } 74 | } 75 | .disabled(isCreating) 76 | .overlay { 77 | if isCreating { 78 | Color.black.opacity(0.3) 79 | .ignoresSafeArea() 80 | .overlay { 81 | ProgressView("Creating post...") 82 | .padding() 83 | .background(.regularMaterial, in: RoundedRectangle(cornerRadius: 12)) 84 | } 85 | } 86 | } 87 | .alert("Error", isPresented: $showingError) { 88 | Button("OK") { } 89 | } message: { 90 | Text(errorMessage) 91 | } 92 | } 93 | } 94 | 95 | private func createPost() async { 96 | isCreating = true 97 | 98 | do { 99 | // Convert NSAttributedString to HTML for storage 100 | let htmlBody = attributedBody.toHTML() 101 | 102 | try await repository.createPost( 103 | title: title.trimmingCharacters(in: .whitespacesAndNewlines), 104 | subtitle: subtitle.trimmingCharacters(in: .whitespacesAndNewlines), 105 | body: attributedBody.string.trimmingCharacters(in: .whitespacesAndNewlines), 106 | htmlBody: htmlBody 107 | ) 108 | dismiss() 109 | } catch { 110 | errorMessage = error.localizedDescription 111 | showingError = true 112 | } 113 | 114 | isCreating = false 115 | } 116 | } 117 | 118 | #Preview { 119 | CreatePostView(repository: PostsRepository()) 120 | } 121 | -------------------------------------------------------------------------------- /PostApp/Views/Posts/PostDetailView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PostDetailView.swift 3 | // PostApp 4 | // 5 | // Created on 23/5/25. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct PostDetailView: View { 11 | let post: Post 12 | let readingGoalRepository: ReadingGoalRepository 13 | @Environment(\.dismiss) private var dismiss 14 | @State private var hasMarkedAsRead = false 15 | 16 | private var formattedDate: String { 17 | let formatter = DateFormatter() 18 | formatter.dateStyle = .long 19 | formatter.timeStyle = .short 20 | return formatter.string(from: post.createdAt) 21 | } 22 | 23 | var body: some View { 24 | NavigationStack { 25 | ScrollView { 26 | VStack(alignment: .leading, spacing: 16) { 27 | VStack(alignment: .leading, spacing: 8) { 28 | Text(post.title) 29 | .font(.largeTitle) 30 | .fontWeight(.bold) 31 | 32 | Text(post.subtitle) 33 | .font(.title3) 34 | .foregroundStyle(.secondary) 35 | 36 | HStack { 37 | Text(formattedDate) 38 | .font(.caption) 39 | .foregroundStyle(.tertiary) 40 | 41 | if readingGoalRepository.hasReadPost(post.id) { 42 | Label("Read", systemImage: "checkmark.circle.fill") 43 | .font(.caption) 44 | .foregroundStyle(.green) 45 | .transition(.scale.combined(with: .opacity)) 46 | } 47 | } 48 | } 49 | .padding(.horizontal) 50 | 51 | Divider() 52 | 53 | // Display rich text content 54 | Text(post.attributedBody) 55 | .font(.body) 56 | .padding(.horizontal) 57 | .textSelection(.enabled) 58 | } 59 | .padding(.vertical) 60 | } 61 | .navigationBarTitleDisplayMode(.inline) 62 | .toolbar { 63 | ToolbarItem(placement: .topBarTrailing) { 64 | Button("Done") { 65 | dismiss() 66 | } 67 | } 68 | } 69 | .task { 70 | // Mark as read after a short delay to ensure the user actually opened the post 71 | if !hasMarkedAsRead { 72 | try? await Task.sleep(nanoseconds: 500_000_000) // 0.5 seconds 73 | await readingGoalRepository.markPostAsRead(post.id) 74 | hasMarkedAsRead = true 75 | } 76 | } 77 | } 78 | } 79 | } 80 | 81 | #Preview { 82 | PostDetailView( 83 | post: Post( 84 | title: "Sample Post Title", 85 | subtitle: "This is a sample subtitle for the post", 86 | body: """ 87 | This is the body content of the post. It can be quite long and contain multiple paragraphs. 88 | 89 | Here's another paragraph with more content to show how the layout works with longer text. 90 | 91 | And a third paragraph to really demonstrate the scrolling functionality. 92 | """, 93 | htmlBody: """ 94 |

This is the body content of the post. It can be quite long and contain multiple paragraphs.

95 | 96 |

Here's another paragraph with more content to show how the layout works with longer text.

97 | 98 |

And a third paragraph to really demonstrate the scrolling functionality.

99 | """ 100 | ), 101 | readingGoalRepository: ReadingGoalRepository() 102 | ) 103 | } 104 | -------------------------------------------------------------------------------- /PostApp/Views/Posts/PostsListView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PostsListView.swift 3 | // PostApp 4 | // 5 | // Created on 23/5/25. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct PostsListView: View { 11 | @State private var repository = PostsRepository() 12 | @State private var readingGoalRepository = ReadingGoalRepository() 13 | @State private var selectedPost: Post? 14 | @State private var showingCreatePost = false 15 | 16 | var body: some View { 17 | NavigationStack { 18 | ScrollView { 19 | VStack(spacing: 20) { 20 | // Reading Goal Widget 21 | ReadingGoalWidget(repository: readingGoalRepository) 22 | .padding(.top, 10) 23 | 24 | // Posts Section 25 | VStack(alignment: .leading, spacing: 16) { 26 | Text("Posts") 27 | .font(.title2.bold()) 28 | .padding(.horizontal) 29 | 30 | if repository.isLoading && repository.posts.isEmpty { 31 | ProgressView("Loading posts...") 32 | .frame(maxWidth: .infinity, minHeight: 200) 33 | } else if repository.posts.isEmpty { 34 | ContentUnavailableView( 35 | "No Posts Yet", 36 | systemImage: "doc.text", 37 | description: Text("Tap the + button to create your first post") 38 | ) 39 | .frame(minHeight: 200) 40 | } else { 41 | LazyVStack(spacing: 12) { 42 | ForEach(repository.posts) { post in 43 | PostCardView( 44 | post: post, 45 | isRead: readingGoalRepository.hasReadPost(post.id) 46 | ) 47 | .contentShape(Rectangle()) 48 | .onTapGesture { 49 | selectedPost = post 50 | } 51 | } 52 | } 53 | .padding(.horizontal) 54 | } 55 | } 56 | } 57 | .padding(.bottom, 20) 58 | } 59 | .refreshable { 60 | await repository.fetchPosts() 61 | } 62 | .navigationTitle("PostApp") 63 | .toolbar { 64 | ToolbarItem(placement: .primaryAction) { 65 | Button { 66 | showingCreatePost = true 67 | } label: { 68 | Image(systemName: "plus") 69 | } 70 | } 71 | } 72 | .task { 73 | await repository.fetchPosts() 74 | } 75 | .sheet(item: $selectedPost) { post in 76 | PostDetailView(post: post, readingGoalRepository: readingGoalRepository) 77 | } 78 | .sheet(isPresented: $showingCreatePost) { 79 | CreatePostView(repository: repository) 80 | } 81 | } 82 | } 83 | } 84 | 85 | // New card view for posts with read indicator 86 | struct PostCardView: View { 87 | let post: Post 88 | let isRead: Bool 89 | 90 | private var formattedDate: String { 91 | let formatter = DateFormatter() 92 | formatter.dateStyle = .medium 93 | formatter.timeStyle = .short 94 | return formatter.string(from: post.createdAt) 95 | } 96 | 97 | var body: some View { 98 | HStack(alignment: .top, spacing: 12) { 99 | // Read indicator 100 | Circle() 101 | .fill(isRead ? Color.green : Color.gray.opacity(0.3)) 102 | .frame(width: 8, height: 8) 103 | .offset(y: 8) 104 | 105 | VStack(alignment: .leading, spacing: 8) { 106 | Text(post.title) 107 | .font(.headline) 108 | .lineLimit(2) 109 | .foregroundStyle(isRead ? .secondary : .primary) 110 | 111 | Text(post.subtitle) 112 | .font(.subheadline) 113 | .lineLimit(2) 114 | .foregroundStyle(isRead ? .tertiary : .secondary) 115 | 116 | HStack { 117 | Text(formattedDate) 118 | .font(.caption) 119 | .foregroundStyle(.tertiary) 120 | 121 | if isRead { 122 | Label("Read", systemImage: "checkmark.circle.fill") 123 | .font(.caption) 124 | .foregroundStyle(.green) 125 | } 126 | } 127 | } 128 | 129 | Spacer() 130 | } 131 | .padding() 132 | .background( 133 | RoundedRectangle(cornerRadius: 12) 134 | .fill(Color(white: isRead ? 0.98 : 0.96)) 135 | .shadow(color: Color.black.opacity(0.05), radius: 4, x: 0, y: 2) 136 | ) 137 | } 138 | } 139 | 140 | #Preview { 141 | PostsListView() 142 | } 143 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PostApp - SwiftUI Blog Application 2 | 3 | A modern SwiftUI blog application built with iOS 18 APIs, featuring a clean architecture and ready for Supabase integration. 4 | 5 | ## Features 6 | 7 | - ✅ Display list of blog posts with title, subtitle, and creation date 8 | - ✅ Navigate to detailed post view by tapping on a post 9 | - ✅ Create new posts using a sheet presentation 10 | - ✅ **Rich Text Editor** with formatting toolbar (Bold, Italic, Underline, Colors, Text Sizes) 11 | - ✅ **HTML Storage** for rich text content with AttributedString display 12 | - ✅ Modern SwiftUI with iOS 18 Observable macro 13 | - ✅ Proper separation of concerns with MVVM architecture 14 | - ✅ Full Supabase integration for data persistence 15 | 16 | ## Architecture 17 | 18 | The app follows a clean architecture pattern with proper separation of concerns: 19 | 20 | ``` 21 | PostApp/ 22 | ├── Models/ 23 | │ └── Post.swift # Post data model 24 | ├── Services/ 25 | │ └── SupabaseService.swift # Service layer for data operations 26 | ├── Repositories/ 27 | │ └── PostsRepository.swift # Repository pattern for state management 28 | ├── Views/ 29 | │ ├── Posts/ 30 | │ │ ├── PostsListView.swift # Main posts list 31 | │ │ ├── PostDetailView.swift # Post detail view 32 | │ │ └── CreatePostView.swift # Create new post sheet 33 | │ └── Components/ 34 | │ ├── PostRowView.swift # Reusable post row component 35 | │ ├── RichTextEditor.swift # Rich text editing component 36 | │ └── RichTextToolbar.swift # Formatting toolbar 37 | └── PostAppApp.swift # App entry point 38 | ``` 39 | 40 | ## Requirements 41 | 42 | - Xcode 15.0 or later 43 | - iOS 17.0 or later 44 | - macOS 14.0 or later (for development) 45 | 46 | ## Getting Started 47 | 48 | 1. Open `PostApp.xcodeproj` in Xcode 49 | 2. Select your target device or simulator 50 | 3. Build and run (⌘+R) 51 | 52 | ## Supabase Integration 53 | 54 | The app includes full Supabase integration with rich text support. Follow these steps to set up your database: 55 | 56 | ### 1. Prerequisites 57 | 58 | The Supabase Swift SDK is already included in the project (version 2.29.0). 59 | 60 | ### 2. Configure Supabase 61 | 62 | Create a `Secret.plist` file in your project with your Supabase credentials: 63 | 64 | ```xml 65 | 66 | 67 | 68 | 69 | supabaseUrl 70 | YOUR_SUPABASE_URL 71 | supabaseKey 72 | YOUR_SUPABASE_ANON_KEY 73 | 74 | 75 | ``` 76 | 77 | ### 3. Database Setup 78 | 79 | Choose one of the following options: 80 | 81 | #### Option A: New Installation 82 | If setting up for the first time, run the complete schema: 83 | 1. Open your Supabase project → SQL Editor 84 | 2. Copy and paste the contents of `PostApp/Database/schema.sql` 85 | 3. Click "Run" 86 | 87 | #### Option B: Existing Installation 88 | If you already have the basic posts table, run the migration: 89 | 1. Open your Supabase project → SQL Editor 90 | 2. Copy and paste the contents of `PostApp/Database/migration_add_html_body.sql` 91 | 3. Click "Run" 92 | 93 | ### 4. Database Schema 94 | 95 | The posts table includes rich text support: 96 | 97 | | Column | Type | Description | 98 | |--------|------|-------------| 99 | | `id` | UUID | Primary key | 100 | | `title` | TEXT | Post title | 101 | | `subtitle` | TEXT | Post subtitle | 102 | | `body` | TEXT | Plain text (fallback) | 103 | | `html_body` | TEXT | Rich text as HTML | 104 | | `created_at` | TIMESTAMP | Creation date | 105 | 106 | See `PostApp/Database/README.md` for complete setup instructions. 107 | 108 | ## Usage 109 | 110 | ### Viewing Posts 111 | - Launch the app to see the list of posts 112 | - Pull down to refresh the posts list 113 | - Tap on any post to view its full content with rich text formatting 114 | 115 | ### Creating Posts with Rich Text 116 | - Tap the "+" button in the navigation bar 117 | - Fill in the title and subtitle 118 | - Use the rich text editor for the body content: 119 | - **Select text** to apply formatting 120 | - **Bold/Italic/Underline**: Tap the respective buttons 121 | - **Text Size**: Use the size menu (Small, Normal, Large, Extra Large) 122 | - **Text Color**: Choose from color palette (Default, Red, Blue, Green, Orange, Purple) 123 | - **Clear Formatting**: Remove all styling from selected text 124 | - Tap "Create" to save the post 125 | 126 | ### Rich Text Formatting 127 | - Select any text in the editor 128 | - Use the toolbar at the bottom of the screen 129 | - Multiple formats can be combined (e.g., bold + italic + colored) 130 | - The toolbar shows which formats are currently active 131 | 132 | ### Post Details 133 | - Tap on any post in the list to view details 134 | - Rich text formatting is preserved and displayed 135 | - Text remains selectable for copying 136 | - Tap "Done" to dismiss the detail view 137 | 138 | ## Key Technologies 139 | 140 | - **SwiftUI**: Modern declarative UI framework 141 | - **iOS 18 Observable**: Latest state management with `@Observable` macro 142 | - **Rich Text Editing**: Custom UITextView integration with formatting toolbar 143 | - **AttributedString**: SwiftUI native rich text display 144 | - **HTML Storage**: Cross-platform rich text format 145 | - **Swift Concurrency**: Async/await for network operations 146 | - **MVVM Architecture**: Clean separation of concerns 147 | - **Repository Pattern**: Centralized data management 148 | - **Supabase**: Full-featured backend with PostgreSQL 149 | 150 | ## Future Enhancements 151 | 152 | ### Rich Text Features 153 | - [ ] Lists (bullet points, numbered lists) 154 | - [ ] Text alignment (left, center, right, justify) 155 | - [ ] Link insertion and editing 156 | - [ ] Image embedding in posts 157 | - [ ] Code blocks with syntax highlighting 158 | - [ ] Undo/redo functionality 159 | - [ ] Markdown import/export 160 | 161 | ### General Features 162 | - [ ] User authentication 163 | - [ ] Edit and delete posts 164 | - [ ] Search functionality (including rich text search) 165 | - [ ] Categories/tags for posts 166 | - [ ] Comments system 167 | - [ ] Offline support with local caching 168 | - [ ] Export posts as PDF/HTML 169 | - [ ] Post drafts and auto-save 170 | 171 | ## License 172 | 173 | This project is available for educational purposes. 174 | -------------------------------------------------------------------------------- /buildServer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "xcode build server", 3 | "version": "0.2", 4 | "bspVersion": "2.0", 5 | "languages": [ 6 | "c", 7 | "cpp", 8 | "objective-c", 9 | "objective-cpp", 10 | "swift" 11 | ], 12 | "argv": [ 13 | "/opt/homebrew/bin/xcode-build-server" 14 | ], 15 | "workspace": "/Users/dimillian/Documents/Dev/xtool/PostApp/PostApp.xcodeproj/project.xcworkspace", 16 | "build_root": "/Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq", 17 | "scheme": "PostApp", 18 | "kind": "xcode" 19 | } -------------------------------------------------------------------------------- /xcodemake -project PostApp.xcodeproj -scheme PostApp -configuration Debug -skipMacroValidation -destination platform=iOS Simulator,id=964CE4CD-CA04-41F8-8581-BA050F50FF2F build.log: -------------------------------------------------------------------------------- 1 | Command line invocation: 2 | /Applications/Xcode-16.4.0-Release.Candidate.app/Contents/Developer/usr/bin/xcodebuild -project PostApp.xcodeproj -scheme PostApp -configuration Debug -skipMacroValidation -destination "platform=iOS Simulator,id=964CE4CD-CA04-41F8-8581-BA050F50FF2F" build 3 | 4 | ComputePackagePrebuildTargetDependencyGraph 5 | 6 | Prepare packages 7 | 8 | CreateBuildRequest 9 | 10 | SendProjectDescription 11 | 12 | CreateBuildOperation 13 | 14 | ComputeTargetDependencyGraph 15 | note: Building targets in dependency order 16 | note: Target dependency graph (1 target) 17 | Target 'PostApp' in project 'PostApp' (no dependencies) 18 | 19 | GatherProvisioningInputs 20 | 21 | CreateBuildDescription 22 | 23 | ExecuteExternalTool /Applications/Xcode-16.4.0-Release.Candidate.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang -v -E -dM -isysroot /Applications/Xcode-16.4.0-Release.Candidate.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator18.5.sdk -x c -c /dev/null 24 | 25 | ExecuteExternalTool /Applications/Xcode-16.4.0-Release.Candidate.app/Contents/Developer/usr/bin/actool --print-asset-tag-combinations --output-format xml1 /Users/dimillian/Documents/Dev/xtool/PostApp/PostApp/Assets.xcassets 26 | 27 | ExecuteExternalTool /Applications/Xcode-16.4.0-Release.Candidate.app/Contents/Developer/usr/bin/actool --version --output-format xml1 28 | 29 | ExecuteExternalTool /Applications/Xcode-16.4.0-Release.Candidate.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swiftc --version 30 | 31 | ExecuteExternalTool /Applications/Xcode-16.4.0-Release.Candidate.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld -version_details 32 | 33 | Build description signature: ad732b62771ec21a6ca863783a4e84da 34 | Build description path: /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/XCBuildData/ad732b62771ec21a6ca863783a4e84da.xcbuilddata 35 | ClangStatCache /Applications/Xcode-16.4.0-Release.Candidate.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang-stat-cache /Applications/Xcode-16.4.0-Release.Candidate.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator18.5.sdk /Users/dimillian/Library/Developer/Xcode/DerivedData/SDKStatCaches.noindex/iphonesimulator18.5-22F76-0fd9317c814c246fffd1a226eb45c7a3.sdkstatcache 36 | cd /Users/dimillian/Documents/Dev/xtool/PostApp/PostApp.xcodeproj 37 | /Applications/Xcode-16.4.0-Release.Candidate.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang-stat-cache /Applications/Xcode-16.4.0-Release.Candidate.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator18.5.sdk -o /Users/dimillian/Library/Developer/Xcode/DerivedData/SDKStatCaches.noindex/iphonesimulator18.5-22F76-0fd9317c814c246fffd1a226eb45c7a3.sdkstatcache 38 | 39 | CreateBuildDirectory /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex 40 | cd /Users/dimillian/Documents/Dev/xtool/PostApp/PostApp.xcodeproj 41 | builtin-create-build-directory /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex 42 | 43 | CreateBuildDirectory /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Products 44 | cd /Users/dimillian/Documents/Dev/xtool/PostApp/PostApp.xcodeproj 45 | builtin-create-build-directory /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Products 46 | 47 | CreateBuildDirectory /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/EagerLinkingTBDs/Debug-iphonesimulator 48 | cd /Users/dimillian/Documents/Dev/xtool/PostApp/PostApp.xcodeproj 49 | builtin-create-build-directory /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/EagerLinkingTBDs/Debug-iphonesimulator 50 | 51 | CreateBuildDirectory /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Products/Debug-iphonesimulator 52 | cd /Users/dimillian/Documents/Dev/xtool/PostApp/PostApp.xcodeproj 53 | builtin-create-build-directory /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Products/Debug-iphonesimulator 54 | 55 | WriteAuxiliaryFile /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp-0d5f3ddae1cf3ac6f10e5e196cf07531-VFS-iphonesimulator/all-product-headers.yaml 56 | cd /Users/dimillian/Documents/Dev/xtool/PostApp/PostApp.xcodeproj 57 | write-file /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp-0d5f3ddae1cf3ac6f10e5e196cf07531-VFS-iphonesimulator/all-product-headers.yaml 58 | 59 | WriteAuxiliaryFile /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/PostApp-DebugDylibPath-normal-arm64.txt (in target 'PostApp' from project 'PostApp') 60 | cd /Users/dimillian/Documents/Dev/xtool/PostApp 61 | write-file /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/PostApp-DebugDylibPath-normal-arm64.txt 62 | 63 | WriteAuxiliaryFile /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/PostApp-DebugDylibInstallName-normal-arm64.txt (in target 'PostApp' from project 'PostApp') 64 | cd /Users/dimillian/Documents/Dev/xtool/PostApp 65 | write-file /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/PostApp-DebugDylibInstallName-normal-arm64.txt 66 | 67 | WriteAuxiliaryFile /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/PostApp-generated-files.hmap (in target 'PostApp' from project 'PostApp') 68 | cd /Users/dimillian/Documents/Dev/xtool/PostApp 69 | write-file /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/PostApp-generated-files.hmap 70 | 71 | WriteAuxiliaryFile /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/PostApp.hmap (in target 'PostApp' from project 'PostApp') 72 | cd /Users/dimillian/Documents/Dev/xtool/PostApp 73 | write-file /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/PostApp.hmap 74 | 75 | WriteAuxiliaryFile /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/PostApp-all-target-headers.hmap (in target 'PostApp' from project 'PostApp') 76 | cd /Users/dimillian/Documents/Dev/xtool/PostApp 77 | write-file /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/PostApp-all-target-headers.hmap 78 | 79 | WriteAuxiliaryFile /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/PostApp-project-headers.hmap (in target 'PostApp' from project 'PostApp') 80 | cd /Users/dimillian/Documents/Dev/xtool/PostApp 81 | write-file /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/PostApp-project-headers.hmap 82 | 83 | WriteAuxiliaryFile /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/PostApp-own-target-headers.hmap (in target 'PostApp' from project 'PostApp') 84 | cd /Users/dimillian/Documents/Dev/xtool/PostApp 85 | write-file /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/PostApp-own-target-headers.hmap 86 | 87 | WriteAuxiliaryFile /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/PostApp.DependencyStaticMetadataFileList (in target 'PostApp' from project 'PostApp') 88 | cd /Users/dimillian/Documents/Dev/xtool/PostApp 89 | write-file /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/PostApp.DependencyStaticMetadataFileList 90 | 91 | WriteAuxiliaryFile /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/PostApp.DependencyMetadataFileList (in target 'PostApp' from project 'PostApp') 92 | cd /Users/dimillian/Documents/Dev/xtool/PostApp 93 | write-file /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/PostApp.DependencyMetadataFileList 94 | 95 | WriteAuxiliaryFile /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/PostApp-all-non-framework-target-headers.hmap (in target 'PostApp' from project 'PostApp') 96 | cd /Users/dimillian/Documents/Dev/xtool/PostApp 97 | write-file /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/PostApp-all-non-framework-target-headers.hmap 98 | 99 | WriteAuxiliaryFile /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/empty-PostApp.plist (in target 'PostApp' from project 'PostApp') 100 | cd /Users/dimillian/Documents/Dev/xtool/PostApp 101 | write-file /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/empty-PostApp.plist 102 | 103 | WriteAuxiliaryFile /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/Objects-normal/arm64/PostApp_const_extract_protocols.json (in target 'PostApp' from project 'PostApp') 104 | cd /Users/dimillian/Documents/Dev/xtool/PostApp 105 | write-file /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/Objects-normal/arm64/PostApp_const_extract_protocols.json 106 | 107 | WriteAuxiliaryFile /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/Objects-normal/arm64/PostApp.SwiftFileList (in target 'PostApp' from project 'PostApp') 108 | cd /Users/dimillian/Documents/Dev/xtool/PostApp 109 | write-file /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/Objects-normal/arm64/PostApp.SwiftFileList 110 | 111 | WriteAuxiliaryFile /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/Objects-normal/arm64/PostApp.SwiftConstValuesFileList (in target 'PostApp' from project 'PostApp') 112 | cd /Users/dimillian/Documents/Dev/xtool/PostApp 113 | write-file /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/Objects-normal/arm64/PostApp.SwiftConstValuesFileList 114 | 115 | WriteAuxiliaryFile /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/Objects-normal/arm64/PostApp-OutputFileMap.json (in target 'PostApp' from project 'PostApp') 116 | cd /Users/dimillian/Documents/Dev/xtool/PostApp 117 | write-file /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/Objects-normal/arm64/PostApp-OutputFileMap.json 118 | 119 | WriteAuxiliaryFile /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/Objects-normal/arm64/PostApp.LinkFileList (in target 'PostApp' from project 'PostApp') 120 | cd /Users/dimillian/Documents/Dev/xtool/PostApp 121 | write-file /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/Objects-normal/arm64/PostApp.LinkFileList 122 | 123 | MkDir /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Products/Debug-iphonesimulator/PostApp.app (in target 'PostApp' from project 'PostApp') 124 | cd /Users/dimillian/Documents/Dev/xtool/PostApp 125 | /bin/mkdir -p /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Products/Debug-iphonesimulator/PostApp.app 126 | 127 | WriteAuxiliaryFile /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/DerivedSources/Entitlements-Simulated.plist (in target 'PostApp' from project 'PostApp') 128 | cd /Users/dimillian/Documents/Dev/xtool/PostApp 129 | write-file /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/DerivedSources/Entitlements-Simulated.plist 130 | 131 | ProcessProductPackaging "" /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/PostApp.app-Simulated.xcent (in target 'PostApp' from project 'PostApp') 132 | cd /Users/dimillian/Documents/Dev/xtool/PostApp 133 | 134 | Entitlements: 135 | 136 | { 137 | "application-identifier" = "Z6P74P6T99.com.legacyAI.PostApp"; 138 | } 139 | 140 | builtin-productPackagingUtility -entitlements -format xml -o /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/PostApp.app-Simulated.xcent 141 | 142 | ProcessProductPackagingDER /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/PostApp.app-Simulated.xcent /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/PostApp.app-Simulated.xcent.der (in target 'PostApp' from project 'PostApp') 143 | cd /Users/dimillian/Documents/Dev/xtool/PostApp 144 | /usr/bin/derq query -f xml -i /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/PostApp.app-Simulated.xcent -o /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/PostApp.app-Simulated.xcent.der --raw 145 | 146 | Ld /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Products/Debug-iphonesimulator/PostApp.app/__preview.dylib normal (in target 'PostApp' from project 'PostApp') 147 | cd /Users/dimillian/Documents/Dev/xtool/PostApp 148 | /Applications/Xcode-16.4.0-Release.Candidate.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang -Xlinker -reproducible -target arm64-apple-ios18.5-simulator -dynamiclib -isysroot /Applications/Xcode-16.4.0-Release.Candidate.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator18.5.sdk -O0 -L/Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Products/Debug-iphonesimulator -F/Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Products/Debug-iphonesimulator -install_name @rpath/PostApp.debug.dylib -dead_strip -rdynamic -Xlinker -no_deduplicate -Xlinker -objc_abi_version -Xlinker 2 -Xlinker -dependency_info -Xlinker /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/Objects-normal/arm64/PostApp_dependency_info.dat -Xlinker -sectcreate -Xlinker __TEXT -Xlinker __entitlements -Xlinker /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/PostApp.app-Simulated.xcent -Xlinker -sectcreate -Xlinker __TEXT -Xlinker __ents_der -Xlinker /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/PostApp.app-Simulated.xcent.der -Xlinker -no_adhoc_codesign -o /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Products/Debug-iphonesimulator/PostApp.app/__preview.dylib 149 | 150 | GenerateAssetSymbols /Users/dimillian/Documents/Dev/xtool/PostApp/PostApp/Assets.xcassets (in target 'PostApp' from project 'PostApp') 151 | cd /Users/dimillian/Documents/Dev/xtool/PostApp 152 | /Applications/Xcode-16.4.0-Release.Candidate.app/Contents/Developer/usr/bin/actool /Users/dimillian/Documents/Dev/xtool/PostApp/PostApp/Assets.xcassets --compile /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Products/Debug-iphonesimulator/PostApp.app --output-format human-readable-text --notices --warnings --export-dependency-info /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/assetcatalog_dependencies --output-partial-info-plist /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/assetcatalog_generated_info.plist --app-icon AppIcon --accent-color AccentColor --compress-pngs --enable-on-demand-resources YES --development-region en --target-device iphone --target-device ipad --minimum-deployment-target 18.5 --platform iphonesimulator --bundle-identifier com.legacyAI.PostApp --generate-swift-asset-symbols /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/DerivedSources/GeneratedAssetSymbols.swift --generate-objc-asset-symbols /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/DerivedSources/GeneratedAssetSymbols.h --generate-asset-symbol-index /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/DerivedSources/GeneratedAssetSymbols-Index.plist 153 | /* com.apple.actool.compilation-results */ 154 | /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/DerivedSources/GeneratedAssetSymbols-Index.plist 155 | /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/DerivedSources/GeneratedAssetSymbols.h 156 | /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/DerivedSources/GeneratedAssetSymbols.swift 157 | 158 | 159 | MkDir /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/assetcatalog_output/thinned (in target 'PostApp' from project 'PostApp') 160 | cd /Users/dimillian/Documents/Dev/xtool/PostApp 161 | /bin/mkdir -p /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/assetcatalog_output/thinned 162 | 163 | MkDir /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/assetcatalog_output/unthinned (in target 'PostApp' from project 'PostApp') 164 | cd /Users/dimillian/Documents/Dev/xtool/PostApp 165 | /bin/mkdir -p /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/assetcatalog_output/unthinned 166 | 167 | CompileAssetCatalogVariant thinned /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Products/Debug-iphonesimulator/PostApp.app /Users/dimillian/Documents/Dev/xtool/PostApp/PostApp/Assets.xcassets (in target 'PostApp' from project 'PostApp') 168 | cd /Users/dimillian/Documents/Dev/xtool/PostApp 169 | /Applications/Xcode-16.4.0-Release.Candidate.app/Contents/Developer/usr/bin/actool /Users/dimillian/Documents/Dev/xtool/PostApp/PostApp/Assets.xcassets --compile /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/assetcatalog_output/thinned --output-format human-readable-text --notices --warnings --export-dependency-info /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/assetcatalog_dependencies_thinned --output-partial-info-plist /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/assetcatalog_generated_info.plist_thinned --app-icon AppIcon --accent-color AccentColor --compress-pngs --enable-on-demand-resources YES --filter-for-thinning-device-configuration iPhone17,3 --filter-for-device-os-version 18.5 --development-region en --target-device iphone --target-device ipad --minimum-deployment-target 18.5 --platform iphonesimulator 170 | /* com.apple.actool.compilation-results */ 171 | /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/assetcatalog_generated_info.plist_thinned 172 | 173 | 174 | LinkAssetCatalog /Users/dimillian/Documents/Dev/xtool/PostApp/PostApp/Assets.xcassets (in target 'PostApp' from project 'PostApp') 175 | cd /Users/dimillian/Documents/Dev/xtool/PostApp 176 | builtin-linkAssetCatalog --thinned /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/assetcatalog_output/thinned --thinned-dependencies /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/assetcatalog_dependencies_thinned --thinned-info-plist-content /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/assetcatalog_generated_info.plist_thinned --unthinned /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/assetcatalog_output/unthinned --unthinned-dependencies /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/assetcatalog_dependencies_unthinned --unthinned-info-plist-content /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/assetcatalog_generated_info.plist_unthinned --output /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Products/Debug-iphonesimulator/PostApp.app --plist-output /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/assetcatalog_generated_info.plist 177 | 178 | ProcessInfoPlistFile /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Products/Debug-iphonesimulator/PostApp.app/Info.plist /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/empty-PostApp.plist (in target 'PostApp' from project 'PostApp') 179 | cd /Users/dimillian/Documents/Dev/xtool/PostApp 180 | builtin-infoPlistUtility /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/empty-PostApp.plist -producttype com.apple.product-type.application -genpkginfo /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Products/Debug-iphonesimulator/PostApp.app/PkgInfo -expandbuildsettings -format binary -platform iphonesimulator -additionalcontentfile /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/assetcatalog_generated_info.plist -o /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Products/Debug-iphonesimulator/PostApp.app/Info.plist 181 | 182 | SwiftDriver PostApp normal arm64 com.apple.xcode.tools.swift.compiler (in target 'PostApp' from project 'PostApp') 183 | cd /Users/dimillian/Documents/Dev/xtool/PostApp 184 | builtin-SwiftDriver -- /Applications/Xcode-16.4.0-Release.Candidate.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swiftc -module-name PostApp -Onone -enforce-exclusivity\=checked @/Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/Objects-normal/arm64/PostApp.SwiftFileList -DDEBUG -enable-bare-slash-regex -enable-experimental-feature DebugDescriptionMacro -sdk /Applications/Xcode-16.4.0-Release.Candidate.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator18.5.sdk -target arm64-apple-ios18.5-simulator -g -module-cache-path /Users/dimillian/Library/Developer/Xcode/DerivedData/ModuleCache.noindex -Xfrontend -serialize-debugging-options -enable-testing -index-store-path /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Index.noindex/DataStore -swift-version 5 -I /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Products/Debug-iphonesimulator -F /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Products/Debug-iphonesimulator -emit-localized-strings -emit-localized-strings-path /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/Objects-normal/arm64 -c -j14 -enable-batch-mode -incremental -Xcc -ivfsstatcache -Xcc /Users/dimillian/Library/Developer/Xcode/DerivedData/SDKStatCaches.noindex/iphonesimulator18.5-22F76-0fd9317c814c246fffd1a226eb45c7a3.sdkstatcache -output-file-map /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/Objects-normal/arm64/PostApp-OutputFileMap.json -use-frontend-parseable-output -save-temps -no-color-diagnostics -serialize-diagnostics -emit-dependencies -emit-module -emit-module-path /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/Objects-normal/arm64/PostApp.swiftmodule -validate-clang-modules-once -clang-build-session-file /Users/dimillian/Library/Developer/Xcode/DerivedData/ModuleCache.noindex/Session.modulevalidation -Xcc -I/Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/swift-overrides.hmap -emit-const-values -Xfrontend -const-gather-protocols-file -Xfrontend /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/Objects-normal/arm64/PostApp_const_extract_protocols.json -Xcc -iquote -Xcc /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/PostApp-generated-files.hmap -Xcc -I/Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/PostApp-own-target-headers.hmap -Xcc -I/Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/PostApp-all-target-headers.hmap -Xcc -iquote -Xcc /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/PostApp-project-headers.hmap -Xcc -I/Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Products/Debug-iphonesimulator/include -Xcc -I/Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/DerivedSources-normal/arm64 -Xcc -I/Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/DerivedSources/arm64 -Xcc -I/Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/DerivedSources -Xcc -DDEBUG\=1 -emit-objc-header -emit-objc-header-path /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/Objects-normal/arm64/PostApp-Swift.h -working-directory /Users/dimillian/Documents/Dev/xtool/PostApp -experimental-emit-module-separately -disable-cmo 185 | 186 | SwiftCompile normal arm64 Compiling\ PostsRepository.swift /Users/dimillian/Documents/Dev/xtool/PostApp/PostApp/Repositories/PostsRepository.swift (in target 'PostApp' from project 'PostApp') 187 | 188 | SwiftCompile normal arm64 /Users/dimillian/Documents/Dev/xtool/PostApp/PostApp/Repositories/PostsRepository.swift (in target 'PostApp' from project 'PostApp') 189 | cd /Users/dimillian/Documents/Dev/xtool/PostApp 190 | 191 | 192 | SwiftCompile normal arm64 Compiling\ PostRowView.swift /Users/dimillian/Documents/Dev/xtool/PostApp/PostApp/Views/Components/PostRowView.swift (in target 'PostApp' from project 'PostApp') 193 | SwiftCompile normal arm64 /Users/dimillian/Documents/Dev/xtool/PostApp/PostApp/Views/Components/PostRowView.swift (in target 'PostApp' from project 'PostApp') 194 | cd /Users/dimillian/Documents/Dev/xtool/PostApp 195 | 196 | 197 | SwiftCompile normal arm64 Compiling\ PostDetailView.swift /Users/dimillian/Documents/Dev/xtool/PostApp/PostApp/Views/Posts/PostDetailView.swift (in target 'PostApp' from project 'PostApp') 198 | SwiftCompile normal arm64 /Users/dimillian/Documents/Dev/xtool/PostApp/PostApp/Views/Posts/PostDetailView.swift (in target 'PostApp' from project 'PostApp') 199 | cd /Users/dimillian/Documents/Dev/xtool/PostApp 200 | 201 | 202 | SwiftCompile normal arm64 Compiling\ SupabaseService.swift /Users/dimillian/Documents/Dev/xtool/PostApp/PostApp/Services/SupabaseService.swift (in target 'PostApp' from project 'PostApp') 203 | 204 | SwiftCompile normal arm64 /Users/dimillian/Documents/Dev/xtool/PostApp/PostApp/Services/SupabaseService.swift (in target 'PostApp' from project 'PostApp') 205 | cd /Users/dimillian/Documents/Dev/xtool/PostApp 206 | 207 | 208 | SwiftCompile normal arm64 Compiling\ CreatePostView.swift /Users/dimillian/Documents/Dev/xtool/PostApp/PostApp/Views/Posts/CreatePostView.swift (in target 'PostApp' from project 'PostApp') 209 | SwiftCompile normal arm64 /Users/dimillian/Documents/Dev/xtool/PostApp/PostApp/Views/Posts/CreatePostView.swift (in target 'PostApp' from project 'PostApp') 210 | cd /Users/dimillian/Documents/Dev/xtool/PostApp 211 | 212 | 213 | SwiftEmitModule normal arm64 Emitting\ module\ for\ PostApp (in target 'PostApp' from project 'PostApp') 214 | 215 | EmitSwiftModule normal arm64 (in target 'PostApp' from project 'PostApp') 216 | cd /Users/dimillian/Documents/Dev/xtool/PostApp 217 | 218 | 219 | SwiftCompile normal arm64 Compiling\ GeneratedAssetSymbols.swift /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/DerivedSources/GeneratedAssetSymbols.swift (in target 'PostApp' from project 'PostApp') 220 | 221 | SwiftCompile normal arm64 /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/DerivedSources/GeneratedAssetSymbols.swift (in target 'PostApp' from project 'PostApp') 222 | cd /Users/dimillian/Documents/Dev/xtool/PostApp 223 | 224 | 225 | SwiftCompile normal arm64 Compiling\ Post.swift /Users/dimillian/Documents/Dev/xtool/PostApp/PostApp/Models/Post.swift (in target 'PostApp' from project 'PostApp') 226 | 227 | SwiftCompile normal arm64 /Users/dimillian/Documents/Dev/xtool/PostApp/PostApp/Models/Post.swift (in target 'PostApp' from project 'PostApp') 228 | cd /Users/dimillian/Documents/Dev/xtool/PostApp 229 | 230 | 231 | SwiftCompile normal arm64 Compiling\ ContentView.swift /Users/dimillian/Documents/Dev/xtool/PostApp/PostApp/ContentView.swift (in target 'PostApp' from project 'PostApp') 232 | 233 | SwiftCompile normal arm64 /Users/dimillian/Documents/Dev/xtool/PostApp/PostApp/ContentView.swift (in target 'PostApp' from project 'PostApp') 234 | cd /Users/dimillian/Documents/Dev/xtool/PostApp 235 | 236 | 237 | SwiftCompile normal arm64 Compiling\ PostsListView.swift /Users/dimillian/Documents/Dev/xtool/PostApp/PostApp/Views/Posts/PostsListView.swift (in target 'PostApp' from project 'PostApp') 238 | 239 | SwiftCompile normal arm64 /Users/dimillian/Documents/Dev/xtool/PostApp/PostApp/Views/Posts/PostsListView.swift (in target 'PostApp' from project 'PostApp') 240 | cd /Users/dimillian/Documents/Dev/xtool/PostApp 241 | 242 | 243 | SwiftCompile normal arm64 Compiling\ PostAppApp.swift /Users/dimillian/Documents/Dev/xtool/PostApp/PostApp/PostAppApp.swift (in target 'PostApp' from project 'PostApp') 244 | 245 | SwiftCompile normal arm64 /Users/dimillian/Documents/Dev/xtool/PostApp/PostApp/PostAppApp.swift (in target 'PostApp' from project 'PostApp') 246 | cd /Users/dimillian/Documents/Dev/xtool/PostApp 247 | 248 | 249 | SwiftDriverJobDiscovery normal arm64 Compiling PostAppApp.swift (in target 'PostApp' from project 'PostApp') 250 | 251 | SwiftDriverJobDiscovery normal arm64 Compiling GeneratedAssetSymbols.swift (in target 'PostApp' from project 'PostApp') 252 | 253 | SwiftDriverJobDiscovery normal arm64 Compiling Post.swift (in target 'PostApp' from project 'PostApp') 254 | 255 | SwiftDriverJobDiscovery normal arm64 Compiling ContentView.swift (in target 'PostApp' from project 'PostApp') 256 | 257 | SwiftDriverJobDiscovery normal arm64 Compiling SupabaseService.swift (in target 'PostApp' from project 'PostApp') 258 | 259 | SwiftDriverJobDiscovery normal arm64 Emitting module for PostApp (in target 'PostApp' from project 'PostApp') 260 | 261 | SwiftDriver\ Compilation\ Requirements PostApp normal arm64 com.apple.xcode.tools.swift.compiler (in target 'PostApp' from project 'PostApp') 262 | cd /Users/dimillian/Documents/Dev/xtool/PostApp 263 | builtin-Swift-Compilation-Requirements -- /Applications/Xcode-16.4.0-Release.Candidate.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swiftc -module-name PostApp -Onone -enforce-exclusivity\=checked @/Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/Objects-normal/arm64/PostApp.SwiftFileList -DDEBUG -enable-bare-slash-regex -enable-experimental-feature DebugDescriptionMacro -sdk /Applications/Xcode-16.4.0-Release.Candidate.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator18.5.sdk -target arm64-apple-ios18.5-simulator -g -module-cache-path /Users/dimillian/Library/Developer/Xcode/DerivedData/ModuleCache.noindex -Xfrontend -serialize-debugging-options -enable-testing -index-store-path /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Index.noindex/DataStore -swift-version 5 -I /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Products/Debug-iphonesimulator -F /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Products/Debug-iphonesimulator -emit-localized-strings -emit-localized-strings-path /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/Objects-normal/arm64 -c -j14 -enable-batch-mode -incremental -Xcc -ivfsstatcache -Xcc /Users/dimillian/Library/Developer/Xcode/DerivedData/SDKStatCaches.noindex/iphonesimulator18.5-22F76-0fd9317c814c246fffd1a226eb45c7a3.sdkstatcache -output-file-map /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/Objects-normal/arm64/PostApp-OutputFileMap.json -use-frontend-parseable-output -save-temps -no-color-diagnostics -serialize-diagnostics -emit-dependencies -emit-module -emit-module-path /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/Objects-normal/arm64/PostApp.swiftmodule -validate-clang-modules-once -clang-build-session-file /Users/dimillian/Library/Developer/Xcode/DerivedData/ModuleCache.noindex/Session.modulevalidation -Xcc -I/Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/swift-overrides.hmap -emit-const-values -Xfrontend -const-gather-protocols-file -Xfrontend /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/Objects-normal/arm64/PostApp_const_extract_protocols.json -Xcc -iquote -Xcc /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/PostApp-generated-files.hmap -Xcc -I/Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/PostApp-own-target-headers.hmap -Xcc -I/Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/PostApp-all-target-headers.hmap -Xcc -iquote -Xcc /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/PostApp-project-headers.hmap -Xcc -I/Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Products/Debug-iphonesimulator/include -Xcc -I/Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/DerivedSources-normal/arm64 -Xcc -I/Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/DerivedSources/arm64 -Xcc -I/Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/DerivedSources -Xcc -DDEBUG\=1 -emit-objc-header -emit-objc-header-path /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/Objects-normal/arm64/PostApp-Swift.h -working-directory /Users/dimillian/Documents/Dev/xtool/PostApp -experimental-emit-module-separately -disable-cmo 264 | 265 | SwiftMergeGeneratedHeaders /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/DerivedSources/PostApp-Swift.h /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/Objects-normal/arm64/PostApp-Swift.h (in target 'PostApp' from project 'PostApp') 266 | cd /Users/dimillian/Documents/Dev/xtool/PostApp 267 | builtin-swiftHeaderTool -arch arm64 /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/Objects-normal/arm64/PostApp-Swift.h -o /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/DerivedSources/PostApp-Swift.h 268 | 269 | Copy /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Products/Debug-iphonesimulator/PostApp.swiftmodule/arm64-apple-ios-simulator.abi.json /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/Objects-normal/arm64/PostApp.abi.json (in target 'PostApp' from project 'PostApp') 270 | cd /Users/dimillian/Documents/Dev/xtool/PostApp 271 | builtin-copy -exclude .DS_Store -exclude CVS -exclude .svn -exclude .git -exclude .hg -resolve-src-symlinks -rename /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/Objects-normal/arm64/PostApp.abi.json /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Products/Debug-iphonesimulator/PostApp.swiftmodule/arm64-apple-ios-simulator.abi.json 272 | 273 | Copy /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Products/Debug-iphonesimulator/PostApp.swiftmodule/arm64-apple-ios-simulator.swiftmodule /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/Objects-normal/arm64/PostApp.swiftmodule (in target 'PostApp' from project 'PostApp') 274 | cd /Users/dimillian/Documents/Dev/xtool/PostApp 275 | builtin-copy -exclude .DS_Store -exclude CVS -exclude .svn -exclude .git -exclude .hg -resolve-src-symlinks -rename /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/Objects-normal/arm64/PostApp.swiftmodule /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Products/Debug-iphonesimulator/PostApp.swiftmodule/arm64-apple-ios-simulator.swiftmodule 276 | 277 | Copy /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Products/Debug-iphonesimulator/PostApp.swiftmodule/arm64-apple-ios-simulator.swiftdoc /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/Objects-normal/arm64/PostApp.swiftdoc (in target 'PostApp' from project 'PostApp') 278 | cd /Users/dimillian/Documents/Dev/xtool/PostApp 279 | builtin-copy -exclude .DS_Store -exclude CVS -exclude .svn -exclude .git -exclude .hg -resolve-src-symlinks -rename /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/Objects-normal/arm64/PostApp.swiftdoc /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Products/Debug-iphonesimulator/PostApp.swiftmodule/arm64-apple-ios-simulator.swiftdoc 280 | 281 | Copy /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Products/Debug-iphonesimulator/PostApp.swiftmodule/Project/arm64-apple-ios-simulator.swiftsourceinfo /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/Objects-normal/arm64/PostApp.swiftsourceinfo (in target 'PostApp' from project 'PostApp') 282 | cd /Users/dimillian/Documents/Dev/xtool/PostApp 283 | builtin-copy -exclude .DS_Store -exclude CVS -exclude .svn -exclude .git -exclude .hg -resolve-src-symlinks -rename /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/Objects-normal/arm64/PostApp.swiftsourceinfo /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Products/Debug-iphonesimulator/PostApp.swiftmodule/Project/arm64-apple-ios-simulator.swiftsourceinfo 284 | 285 | SwiftDriverJobDiscovery normal arm64 Compiling PostsRepository.swift (in target 'PostApp' from project 'PostApp') 286 | 287 | SwiftDriverJobDiscovery normal arm64 Compiling PostRowView.swift (in target 'PostApp' from project 'PostApp') 288 | 289 | SwiftDriverJobDiscovery normal arm64 Compiling PostDetailView.swift (in target 'PostApp' from project 'PostApp') 290 | 291 | SwiftDriverJobDiscovery normal arm64 Compiling PostsListView.swift (in target 'PostApp' from project 'PostApp') 292 | 293 | SwiftDriverJobDiscovery normal arm64 Compiling CreatePostView.swift (in target 'PostApp' from project 'PostApp') 294 | 295 | SwiftDriver\ Compilation PostApp normal arm64 com.apple.xcode.tools.swift.compiler (in target 'PostApp' from project 'PostApp') 296 | cd /Users/dimillian/Documents/Dev/xtool/PostApp 297 | builtin-Swift-Compilation -- /Applications/Xcode-16.4.0-Release.Candidate.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swiftc -module-name PostApp -Onone -enforce-exclusivity\=checked @/Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/Objects-normal/arm64/PostApp.SwiftFileList -DDEBUG -enable-bare-slash-regex -enable-experimental-feature DebugDescriptionMacro -sdk /Applications/Xcode-16.4.0-Release.Candidate.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator18.5.sdk -target arm64-apple-ios18.5-simulator -g -module-cache-path /Users/dimillian/Library/Developer/Xcode/DerivedData/ModuleCache.noindex -Xfrontend -serialize-debugging-options -enable-testing -index-store-path /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Index.noindex/DataStore -swift-version 5 -I /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Products/Debug-iphonesimulator -F /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Products/Debug-iphonesimulator -emit-localized-strings -emit-localized-strings-path /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/Objects-normal/arm64 -c -j14 -enable-batch-mode -incremental -Xcc -ivfsstatcache -Xcc /Users/dimillian/Library/Developer/Xcode/DerivedData/SDKStatCaches.noindex/iphonesimulator18.5-22F76-0fd9317c814c246fffd1a226eb45c7a3.sdkstatcache -output-file-map /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/Objects-normal/arm64/PostApp-OutputFileMap.json -use-frontend-parseable-output -save-temps -no-color-diagnostics -serialize-diagnostics -emit-dependencies -emit-module -emit-module-path /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/Objects-normal/arm64/PostApp.swiftmodule -validate-clang-modules-once -clang-build-session-file /Users/dimillian/Library/Developer/Xcode/DerivedData/ModuleCache.noindex/Session.modulevalidation -Xcc -I/Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/swift-overrides.hmap -emit-const-values -Xfrontend -const-gather-protocols-file -Xfrontend /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/Objects-normal/arm64/PostApp_const_extract_protocols.json -Xcc -iquote -Xcc /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/PostApp-generated-files.hmap -Xcc -I/Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/PostApp-own-target-headers.hmap -Xcc -I/Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/PostApp-all-target-headers.hmap -Xcc -iquote -Xcc /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/PostApp-project-headers.hmap -Xcc -I/Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Products/Debug-iphonesimulator/include -Xcc -I/Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/DerivedSources-normal/arm64 -Xcc -I/Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/DerivedSources/arm64 -Xcc -I/Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/DerivedSources -Xcc -DDEBUG\=1 -emit-objc-header -emit-objc-header-path /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/Objects-normal/arm64/PostApp-Swift.h -working-directory /Users/dimillian/Documents/Dev/xtool/PostApp -experimental-emit-module-separately -disable-cmo 298 | 299 | Ld /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Products/Debug-iphonesimulator/PostApp.app/PostApp.debug.dylib normal (in target 'PostApp' from project 'PostApp') 300 | cd /Users/dimillian/Documents/Dev/xtool/PostApp 301 | /Applications/Xcode-16.4.0-Release.Candidate.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang -Xlinker -reproducible -target arm64-apple-ios18.5-simulator -dynamiclib -isysroot /Applications/Xcode-16.4.0-Release.Candidate.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator18.5.sdk -O0 -L/Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/EagerLinkingTBDs/Debug-iphonesimulator -L/Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Products/Debug-iphonesimulator -F/Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/EagerLinkingTBDs/Debug-iphonesimulator -F/Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Products/Debug-iphonesimulator -filelist /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/Objects-normal/arm64/PostApp.LinkFileList -install_name @rpath/PostApp.debug.dylib -Xlinker -rpath -Xlinker @executable_path/Frameworks -dead_strip -Xlinker -object_path_lto -Xlinker /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/Objects-normal/arm64/PostApp_lto.o -rdynamic -Xlinker -no_deduplicate -Xlinker -objc_abi_version -Xlinker 2 -Xlinker -dependency_info -Xlinker /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/Objects-normal/arm64/PostApp_dependency_info.dat -fobjc-link-runtime -L/Applications/Xcode-16.4.0-Release.Candidate.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/iphonesimulator -L/usr/lib/swift -Xlinker -add_ast_path -Xlinker /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/Objects-normal/arm64/PostApp.swiftmodule -Xlinker -alias -Xlinker _main -Xlinker ___debug_main_executable_dylib_entry_point -Xlinker -no_adhoc_codesign -o /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Products/Debug-iphonesimulator/PostApp.app/PostApp.debug.dylib 302 | 303 | ConstructStubExecutorLinkFileList /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/PostApp-ExecutorLinkFileList-normal-arm64.txt (in target 'PostApp' from project 'PostApp') 304 | cd /Users/dimillian/Documents/Dev/xtool/PostApp 305 | construct-stub-executor-link-file-list /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Products/Debug-iphonesimulator/PostApp.app/PostApp.debug.dylib /Applications/Xcode-16.4.0-Release.Candidate.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/usr/lib/libPreviewsJITStubExecutor_no_swift_entry_point.a /Applications/Xcode-16.4.0-Release.Candidate.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/usr/lib/libPreviewsJITStubExecutor.a --output /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/PostApp-ExecutorLinkFileList-normal-arm64.txt 306 | note: Using stub executor library with Swift entry point. (in target 'PostApp' from project 'PostApp') 307 | 308 | Ld /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Products/Debug-iphonesimulator/PostApp.app/PostApp normal (in target 'PostApp' from project 'PostApp') 309 | cd /Users/dimillian/Documents/Dev/xtool/PostApp 310 | /Applications/Xcode-16.4.0-Release.Candidate.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang -Xlinker -reproducible -target arm64-apple-ios18.5-simulator -isysroot /Applications/Xcode-16.4.0-Release.Candidate.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator18.5.sdk -O0 -L/Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Products/Debug-iphonesimulator -F/Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Products/Debug-iphonesimulator -Xlinker -rpath -Xlinker @executable_path -Xlinker -rpath -Xlinker @executable_path/Frameworks -rdynamic -Xlinker -no_deduplicate -Xlinker -objc_abi_version -Xlinker 2 -e ___debug_blank_executor_main -Xlinker -sectcreate -Xlinker __TEXT -Xlinker __debug_dylib -Xlinker /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/PostApp-DebugDylibPath-normal-arm64.txt -Xlinker -sectcreate -Xlinker __TEXT -Xlinker __debug_instlnm -Xlinker /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/PostApp-DebugDylibInstallName-normal-arm64.txt -Xlinker -filelist -Xlinker /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/PostApp-ExecutorLinkFileList-normal-arm64.txt -Xlinker -sectcreate -Xlinker __TEXT -Xlinker __entitlements -Xlinker /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/PostApp.app-Simulated.xcent -Xlinker -sectcreate -Xlinker __TEXT -Xlinker __ents_der -Xlinker /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/PostApp.app-Simulated.xcent.der /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Products/Debug-iphonesimulator/PostApp.app/PostApp.debug.dylib -Xlinker -no_adhoc_codesign -o /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Products/Debug-iphonesimulator/PostApp.app/PostApp 311 | 312 | CopySwiftLibs /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Products/Debug-iphonesimulator/PostApp.app (in target 'PostApp' from project 'PostApp') 313 | cd /Users/dimillian/Documents/Dev/xtool/PostApp 314 | builtin-swiftStdLibTool --copy --verbose --sign - --scan-executable /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Products/Debug-iphonesimulator/PostApp.app/PostApp.debug.dylib --scan-folder /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Products/Debug-iphonesimulator/PostApp.app/Frameworks --scan-folder /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Products/Debug-iphonesimulator/PostApp.app/PlugIns --scan-folder /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Products/Debug-iphonesimulator/PostApp.app/SystemExtensions --scan-folder /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Products/Debug-iphonesimulator/PostApp.app/Extensions --platform iphonesimulator --toolchain /Applications/Xcode-16.4.0-Release.Candidate.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain --destination /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Products/Debug-iphonesimulator/PostApp.app/Frameworks --strip-bitcode --strip-bitcode-tool /Applications/Xcode-16.4.0-Release.Candidate.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/bitcode_strip --emit-dependency-info /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/SwiftStdLibToolInputDependencies.dep --filter-for-swift-os 315 | 316 | ExtractAppIntentsMetadata (in target 'PostApp' from project 'PostApp') 317 | cd /Users/dimillian/Documents/Dev/xtool/PostApp 318 | /Applications/Xcode-16.4.0-Release.Candidate.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/appintentsmetadataprocessor --toolchain-dir /Applications/Xcode-16.4.0-Release.Candidate.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain --module-name PostApp --sdk-root /Applications/Xcode-16.4.0-Release.Candidate.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator18.5.sdk --xcode-version 16F6 --platform-family iOS --deployment-target 18.5 --bundle-identifier com.legacyAI.PostApp --output /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Products/Debug-iphonesimulator/PostApp.app --target-triple arm64-apple-ios18.5-simulator --binary-file /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Products/Debug-iphonesimulator/PostApp.app/PostApp --dependency-file /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/Objects-normal/arm64/PostApp_dependency_info.dat --stringsdata-file /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/Objects-normal/arm64/ExtractedAppShortcutsMetadata.stringsdata --source-file-list /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/Objects-normal/arm64/PostApp.SwiftFileList --metadata-file-list /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/PostApp.DependencyMetadataFileList --static-metadata-file-list /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/PostApp.DependencyStaticMetadataFileList --swift-const-vals-list /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/Objects-normal/arm64/PostApp.SwiftConstValuesFileList --compile-time-extraction --deployment-aware-processing --validate-assistant-intents --no-app-shortcuts-localization 319 | 2025-05-23 13:32:57.559 appintentsmetadataprocessor[58053:7976765] Starting appintentsmetadataprocessor export 320 | 2025-05-23 13:32:57.560 appintentsmetadataprocessor[58053:7976765] warning: Metadata extraction skipped. No AppIntents.framework dependency found. 321 | 322 | AppIntentsSSUTraining (in target 'PostApp' from project 'PostApp') 323 | cd /Users/dimillian/Documents/Dev/xtool/PostApp 324 | /Applications/Xcode-16.4.0-Release.Candidate.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/appintentsnltrainingprocessor --infoplist-path /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Products/Debug-iphonesimulator/PostApp.app/Info.plist --temp-dir-path /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/ssu --bundle-id com.legacyAI.PostApp --product-path /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Products/Debug-iphonesimulator/PostApp.app --extracted-metadata-path /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Products/Debug-iphonesimulator/PostApp.app/Metadata.appintents --metadata-file-list /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Intermediates.noindex/PostApp.build/Debug-iphonesimulator/PostApp.build/PostApp.DependencyMetadataFileList --archive-ssu-assets 325 | 2025-05-23 13:32:57.573 appintentsnltrainingprocessor[58054:7976766] Parsing options for appintentsnltrainingprocessor 326 | 2025-05-23 13:32:57.574 appintentsnltrainingprocessor[58054:7976766] No AppShortcuts found - Skipping. 327 | 328 | CodeSign /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Products/Debug-iphonesimulator/PostApp.app/PostApp.debug.dylib (in target 'PostApp' from project 'PostApp') 329 | cd /Users/dimillian/Documents/Dev/xtool/PostApp 330 | 331 | Signing Identity: "Sign to Run Locally" 332 | 333 | /usr/bin/codesign --force --sign - --timestamp\=none --generate-entitlement-der /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Products/Debug-iphonesimulator/PostApp.app/PostApp.debug.dylib 334 | 335 | CodeSign /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Products/Debug-iphonesimulator/PostApp.app/__preview.dylib (in target 'PostApp' from project 'PostApp') 336 | cd /Users/dimillian/Documents/Dev/xtool/PostApp 337 | 338 | Signing Identity: "Sign to Run Locally" 339 | 340 | /usr/bin/codesign --force --sign - --timestamp\=none --generate-entitlement-der /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Products/Debug-iphonesimulator/PostApp.app/__preview.dylib 341 | 342 | CodeSign /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Products/Debug-iphonesimulator/PostApp.app (in target 'PostApp' from project 'PostApp') 343 | cd /Users/dimillian/Documents/Dev/xtool/PostApp 344 | 345 | Signing Identity: "Sign to Run Locally" 346 | 347 | /usr/bin/codesign --force --sign - --timestamp\=none --generate-entitlement-der /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Products/Debug-iphonesimulator/PostApp.app 348 | 349 | RegisterExecutionPolicyException /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Products/Debug-iphonesimulator/PostApp.app (in target 'PostApp' from project 'PostApp') 350 | cd /Users/dimillian/Documents/Dev/xtool/PostApp 351 | builtin-RegisterExecutionPolicyException /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Products/Debug-iphonesimulator/PostApp.app 352 | 353 | Validate /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Products/Debug-iphonesimulator/PostApp.app (in target 'PostApp' from project 'PostApp') 354 | cd /Users/dimillian/Documents/Dev/xtool/PostApp 355 | builtin-validationUtility /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Products/Debug-iphonesimulator/PostApp.app -infoplist-subpath Info.plist 356 | 357 | Touch /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Products/Debug-iphonesimulator/PostApp.app (in target 'PostApp' from project 'PostApp') 358 | cd /Users/dimillian/Documents/Dev/xtool/PostApp 359 | /usr/bin/touch -c /Users/dimillian/Library/Developer/Xcode/DerivedData/PostApp-akmidjlkumxkrzalrnmdcqpqbkhq/Build/Products/Debug-iphonesimulator/PostApp.app 360 | 361 | ** BUILD SUCCEEDED ** 362 | 363 | --------------------------------------------------------------------------------