From e7e5b36303be36833932d22eb80fac921c735416 Mon Sep 17 00:00:00 2001 From: ChrisLi <8294252+automactic@users.noreply.github.com> Date: Sat, 21 Oct 2023 17:52:27 -0400 Subject: [PATCH] Dependency versions & C++ interop (#531) * modulemap * about * lint * about * attributes * about * about * lint * project --- .swiftlint.yml | 3 +- Kiwix.xcodeproj/project.pbxproj | 29 ++++- .../{module.modulemap => CoreKiwix.modulemap} | 0 Views/BuildingBlocks/Attribute.swift | 43 ++++++ Views/Library/ZimFileDetail.swift | 34 ----- Views/Settings/About.swift | 122 +++++++++--------- Views/Settings/LanguageSelector.swift | 5 +- Views/Settings/Settings.swift | 2 +- 8 files changed, 136 insertions(+), 102 deletions(-) rename Support/{module.modulemap => CoreKiwix.modulemap} (100%) create mode 100644 Views/BuildingBlocks/Attribute.swift diff --git a/.swiftlint.yml b/.swiftlint.yml index c76b3735..e75411cc 100644 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -1,5 +1,4 @@ disabled_rules: - trailing_whitespace included: - - iOS/Controller/LibraryViewController.swift - - iOS/Controller/SettingsViewController.swift \ No newline at end of file + - Views/Settings/ \ No newline at end of file diff --git a/Kiwix.xcodeproj/project.pbxproj b/Kiwix.xcodeproj/project.pbxproj index 8f1b744e..922d260d 100644 --- a/Kiwix.xcodeproj/project.pbxproj +++ b/Kiwix.xcodeproj/project.pbxproj @@ -11,6 +11,7 @@ 9709C0982A8E4C5700E4564C /* Commands.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9709C0972A8E4C5700E4564C /* Commands.swift */; }; 97121EBE28849F0000371AEB /* ZimFileMissingIndicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97121EBC28849F0000371AEB /* ZimFileMissingIndicator.swift */; }; 97176AD22A4FBD710093E3B0 /* BrowserViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97176AD12A4FBD710093E3B0 /* BrowserViewModel.swift */; }; + 972096E72AE421C300B378B0 /* Attribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = 972096E62AE421C300B378B0 /* Attribute.swift */; }; 9721BBB72841C16D005C910D /* Message.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97FB4B0A27B819A90055F86E /* Message.swift */; }; 9721BBBB28427A93005C910D /* Bookmarks.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9721BBB928427A93005C910D /* Bookmarks.swift */; }; 9724FC3028D5F5BE001B7DD2 /* BookmarkContextMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9724FC2E28D5F5BE001B7DD2 /* BookmarkContextMenu.swift */; }; @@ -132,7 +133,9 @@ 9709C0972A8E4C5700E4564C /* Commands.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Commands.swift; sourceTree = ""; }; 970EC3AB23BCF31F008DCA27 /* ParserTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParserTests.swift; sourceTree = ""; }; 97121EBC28849F0000371AEB /* ZimFileMissingIndicator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZimFileMissingIndicator.swift; sourceTree = ""; }; + 9713F7782AE416E5007DD9EC /* CoreKiwix.modulemap */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.module-map"; path = CoreKiwix.modulemap; sourceTree = ""; }; 97176AD12A4FBD710093E3B0 /* BrowserViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrowserViewModel.swift; sourceTree = ""; }; + 972096E62AE421C300B378B0 /* Attribute.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Attribute.swift; sourceTree = ""; }; 9721BBB928427A93005C910D /* Bookmarks.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Bookmarks.swift; sourceTree = ""; }; 9724FC2E28D5F5BE001B7DD2 /* BookmarkContextMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BookmarkContextMenu.swift; sourceTree = ""; }; 97255D8B273608C3002B995B /* WebView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebView.swift; sourceTree = ""; }; @@ -221,7 +224,6 @@ 97DE2BA1283A8E5C00C63D9B /* LibraryViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LibraryViewModel.swift; sourceTree = ""; }; 97DE2BA4283A944100C63D9B /* GridCommon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GridCommon.swift; sourceTree = ""; }; 97E88F4C2AE407320037F0E5 /* CoreKiwix.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; path = CoreKiwix.xcframework; sourceTree = ""; }; - 97E88F512AE40F9D0037F0E5 /* module.modulemap */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.module-map"; path = module.modulemap; sourceTree = ""; }; 97E94B1D271EF250005B0295 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 97E94B22271EF250005B0295 /* Kiwix.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Kiwix.entitlements; sourceTree = ""; }; 97F3332E28AFC1A2007FF53C /* SearchResults.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchResults.swift; sourceTree = ""; }; @@ -395,6 +397,7 @@ isa = PBXGroup; children = ( 97486D05284A36790096E4DD /* ArticleCell.swift */, + 972096E62AE421C300B378B0 /* Attribute.swift */, 97341C6C2852248500BC273E /* DownloadTaskCell.swift */, 97B0737527825E3D007C7DF3 /* Favicon.swift */, 973A2FCD277FB03F00BD4320 /* FlavorTag.swift */, @@ -540,11 +543,11 @@ isa = PBXGroup; children = ( 97E94B1D271EF250005B0295 /* Assets.xcassets */, + 9713F7782AE416E5007DD9EC /* CoreKiwix.modulemap */, 97B707042974637200562392 /* Info.plist */, 9735B88B279D9A74005F0D1A /* injection.js */, 97E94B22271EF250005B0295 /* Kiwix.entitlements */, 9779A5D02456796A00F6F6FF /* Kiwix-Bridging-Header.h */, - 97E88F512AE40F9D0037F0E5 /* module.modulemap */, 970885D0271339A300C5795C /* wikipedia_dark.css */, ); path = Support; @@ -576,6 +579,7 @@ buildConfigurationList = 972DE4B32814A3D9004FD9B9 /* Build configuration list for PBXNativeTarget "Kiwix" */; buildPhases = ( 97E88F502AE409630037F0E5 /* Run Script */, + 972096E52AE41ED000B378B0 /* ShellScript */, 972DE4A22814A3D8004FD9B9 /* Sources */, 972DE4A32814A3D8004FD9B9 /* Frameworks */, 972DE4A42814A3D8004FD9B9 /* Resources */, @@ -695,6 +699,24 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ + 972096E52AE41ED000B378B0 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "# SwiftLint\n\nif [[ \"$(uname -m)\" == arm64 ]]; then\n export PATH=\"/opt/homebrew/bin:$PATH\"\nfi\n\nif which swiftlint > /dev/null; then\n swiftlint\nelse\n echo \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi\n"; + }; 97E88F502AE409630037F0E5 /* Run Script */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; @@ -712,7 +734,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "# Copy Clang module map to xcframework for Swift C++ Interoperability \n\nrm CoreKiwix.xcframework/ios-arm64/Headers/module.modulemap\nrm CoreKiwix.xcframework/ios-arm64_x86_64-simulator/Headers/module.modulemap\nrm CoreKiwix.xcframework/macos-arm64_x86_64/Headers/module.modulemap\n\ncp Support/module.modulemap CoreKiwix.xcframework/ios-arm64/Headers\ncp Support/module.modulemap CoreKiwix.xcframework/ios-arm64_x86_64-simulator/Headers\ncp Support/module.modulemap CoreKiwix.xcframework/macos-arm64_x86_64/Headers\n"; + shellScript = "# Copy Clang module map to xcframework for Swift C++ Interoperability \n\ncp Support/CoreKiwix.modulemap CoreKiwix.xcframework/ios-arm64/Headers/module.modulemap\ncp Support/CoreKiwix.modulemap CoreKiwix.xcframework/ios-arm64_x86_64-simulator/Headers/module.modulemap\ncp Support/CoreKiwix.modulemap CoreKiwix.xcframework/macos-arm64_x86_64/Headers/module.modulemap\n"; }; /* End PBXShellScriptBuildPhase section */ @@ -768,6 +790,7 @@ 972727AE2A897FAA00BCAF75 /* GridSection.swift in Sources */, 9709C0982A8E4C5700E4564C /* Commands.swift in Sources */, 972727BF2A8A52DC00BCAF75 /* AlertHandler.swift in Sources */, + 972096E72AE421C300B378B0 /* Attribute.swift in Sources */, 97341C6E2852248500BC273E /* DownloadTaskCell.swift in Sources */, 973206552AA28FF7003A1A8F /* TabsManagerButton.swift in Sources */, 976D90DC281586B400CC7D29 /* ZimFileCell.swift in Sources */, diff --git a/Support/module.modulemap b/Support/CoreKiwix.modulemap similarity index 100% rename from Support/module.modulemap rename to Support/CoreKiwix.modulemap diff --git a/Views/BuildingBlocks/Attribute.swift b/Views/BuildingBlocks/Attribute.swift new file mode 100644 index 00000000..038f9202 --- /dev/null +++ b/Views/BuildingBlocks/Attribute.swift @@ -0,0 +1,43 @@ +// +// Attribute.swift +// Kiwix +// +// Created by Chris Li on 10/21/23. +// Copyright © 2023 Chris Li. All rights reserved. +// + +import SwiftUI + +struct Attribute: View { + let title: String + let detail: String? + + var body: some View { + HStack { + Text(title) + Spacer() + Text(detail ?? "Unknown").foregroundColor(.secondary) + } + } +} + +struct AttributeBool: View { + let title: String + let detail: Bool + + var body: some View { + HStack { + Text(title) + Spacer() + #if os(macOS) + Text(detail ? "Yes" : "No").foregroundColor(.secondary) + #elseif os(iOS) + if detail { + Image(systemName: "checkmark.circle.fill").foregroundColor(.green) + } else { + Image(systemName: "multiply.circle.fill").foregroundColor(.orange) + } + #endif + } + } +} diff --git a/Views/Library/ZimFileDetail.swift b/Views/Library/ZimFileDetail.swift index 9ac81656..72b0d948 100644 --- a/Views/Library/ZimFileDetail.swift +++ b/Views/Library/ZimFileDetail.swift @@ -280,40 +280,6 @@ private struct DownloadTaskDetail: View { } } -private struct Attribute: View { - let title: String - let detail: String? - - var body: some View { - HStack { - Text(title) - Spacer() - Text(detail ?? "Unknown").foregroundColor(.secondary) - } - } -} - -private struct AttributeBool: View { - let title: String - let detail: Bool - - var body: some View { - HStack { - Text(title) - Spacer() - #if os(macOS) - Text(detail ? "Yes" : "No").foregroundColor(.secondary) - #elseif os(iOS) - if detail { - Image(systemName: "checkmark.circle.fill").foregroundColor(.green) - } else { - Image(systemName: "multiply.circle.fill").foregroundColor(.orange) - } - #endif - } - } -} - private struct Action: View { let title: String let isDestructive: Bool diff --git a/Views/Settings/About.swift b/Views/Settings/About.swift index 18b19562..09ea7bf0 100644 --- a/Views/Settings/About.swift +++ b/Views/Settings/About.swift @@ -8,18 +8,12 @@ import SwiftUI +import CoreKiwix + struct About: View { + @State private var dependencies = [Dependency]() @State private var externalLinkURL: URL? - private let dependencies = [ - Dependency(name: "libkiwix", license: "GPLv3", version: ZimFileService.shared.libkiwixVersion), - Dependency(name: "libzim", license: "GPLv2", version: ZimFileService.shared.libzimVersion), - Dependency(name: "Xapian", license: "GPLv2", version: nil), - Dependency(name: "ICU", license: "ICU", version: nil), - Dependency(name: "Defaults", license: "MIT", version: "6.3.0"), - Dependency(name: "Fuzi", license: "MIT", version: "3.1.3") - ] - var body: some View { #if os(macOS) VStack(spacing: 16) { @@ -37,13 +31,14 @@ struct About: View { SettingSection(name: "Dependencies", alignment: .top) { Table(dependencies) { TableColumn("Name", value: \.name) - TableColumn("License", value: \.license) - TableColumn("Version") { dependency in Text(dependency.version ?? "") } + TableColumn("License") { dependency in Text(dependency.license ?? "") } + TableColumn("Version", value: \.version) }.tableStyle(.bordered(alternatesRowBackgrounds: true)) } } .padding() .tabItem { Label("About", systemImage: "info.circle") } + .task { await getDependencies() } .onChange(of: externalLinkURL) { url in guard let url = url else { return } NSWorkspace.shared.open(url) @@ -54,33 +49,35 @@ struct About: View { about ourWebsite } - Section { + Section("Release") { release appVersion buildNumber source license - } header: { Text("Release") } - Section { + } + Section("Dependencies") { ForEach(dependencies) { dependency in HStack { Text(dependency.name) Spacer() - Text(dependency.license).foregroundColor(.secondary) - if let version = dependency.version { - Text("(\(version))").foregroundColor(.secondary) + if let license = dependency.license { + Text("\(license) (\(dependency.version))").foregroundColor(.secondary) + } else { + Text(dependency.version).foregroundColor(.secondary) } } } - } header: { Text("Dependencies") } + } } .navigationTitle("About") .navigationBarTitleDisplayMode(.inline) .sheet(item: $externalLinkURL) { SafariView(url: $0) } + .task { await getDependencies() } #endif } - var about: some View { + private var about: some View { Text( """ Kiwix is an offline reader for online content like Wikipedia, Project Gutenberg, or TED Talks. \ @@ -88,64 +85,71 @@ struct About: View { The software as well as the content is free to use for anyone. """ ) - .lineLimit(nil) - .minimumScaleFactor(0.5) // to avoid unnecessary truncation (three dots) } - var release: some View { + private var release: some View { Text("This app is released under the terms of the GNU General Public License version 3.") } - var appVersion: some View { - HStack { - Text("Version") - Spacer() - if let version = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String { - Text(version).foregroundColor(.secondary) - } + private var appVersion: some View { + Attribute(title: "Version", detail: Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String) + } + + private var buildNumber: some View { + Attribute(title: "Build", detail: Bundle.main.infoDictionary?["CFBundleVersion"] as? String) + } + + private var ourWebsite: some View { + Button("Our Website") { + externalLinkURL = URL(string: "https://www.kiwix.org") } } - var buildNumber: some View { - HStack { - Text("Build") - Spacer() - if let build = Bundle.main.infoDictionary?["CFBundleVersion"] as? String { - Text(build).foregroundColor(.secondary) - } + private var source: some View { + Button("Source") { + externalLinkURL = URL(string: "https://github.com/kiwix/apple") } } - var ourWebsite: some View { - Button("Our Website") { externalLinkURL = URL(string: "https://www.kiwix.org") } - } - - var source: some View { - Button("Source") { externalLinkURL = URL(string: "https://github.com/kiwix/apple") } - } - - var license: some View { + private var license: some View { Button("GNU General Public License v3") { externalLinkURL = URL(string: "https://www.gnu.org/licenses/gpl-3.0.en.html") } } - struct Dependency: Identifiable { - var id: String { name } - - let name: String - let license: String - let version: String? + private func getDependencies() async { + dependencies = kiwix.getVersions().map { datum in + Dependency(name: String(datum.first), version: String(datum.second)) + } } } -struct About_Previews: PreviewProvider { - static var previews: some View { - #if os(macOS) - TabView { About() }.preferredColorScheme(.light) - TabView { About() }.preferredColorScheme(.dark) - #elseif os(iOS) - NavigationView { About() } - #endif +private struct Dependency: Identifiable { + var id: String { name } + + let name: String + let version: String + + var license: String? { + switch name { + case "libkiwix": + "GPLv3" + case "libzim": + "GPLv2" + case "libxapian": + "GPLv2" + case "libicu": + "ICU" + default: + nil + } } } + +#Preview { + #if os(macOS) + TabView { About() } + #elseif os(iOS) + NavigationView { About() } + #endif +} diff --git a/Views/Settings/LanguageSelector.swift b/Views/Settings/LanguageSelector.swift index b89b769f..8dcaf387 100644 --- a/Views/Settings/LanguageSelector.swift +++ b/Views/Settings/LanguageSelector.swift @@ -48,7 +48,7 @@ struct LanguageSelector: View { @State private var hiding = [Language]() var body: some View { - List() { + List { Section { if showing.isEmpty { Text("No language").foregroundColor(.secondary) @@ -84,7 +84,7 @@ struct LanguageSelector: View { hiding = languages.filter { !Defaults[.libraryLanguageCodes].contains($0.code) } } } - .onChange(of: sortingMode) { sortingMode in + .onChange(of: sortingMode) { _ in showing.sort(by: Languages.compare(lhs:rhs:)) hiding.sort(by: Languages.compare(lhs:rhs:)) } @@ -122,7 +122,6 @@ private struct LanguageLabel: View { } #endif - private class Languages { /// Retrieve a list of languages. /// - Returns: languages with count of zim files in each language diff --git a/Views/Settings/Settings.swift b/Views/Settings/Settings.swift index fd661050..71f652a3 100644 --- a/Views/Settings/Settings.swift +++ b/Views/Settings/Settings.swift @@ -202,7 +202,7 @@ struct Settings: View { Section("Misc") { Button("Feedback") { UIApplication.shared.open(URL(string: "mailto:feedback@kiwix.org")!) } Button("Rate the App") { - let url = URL(string:"itms-apps://itunes.apple.com/us/app/kiwix/id997079563?action=write-review")! + let url = URL(string: "itms-apps://itunes.apple.com/us/app/kiwix/id997079563?action=write-review")! UIApplication.shared.open(url) } NavigationLink("About") { About() }