├── .github ├── FUNDING.yml └── workflows │ └── build.yaml ├── .gitignore ├── .gitmodules ├── Bookmarks.xcworkspace ├── contents.xcworkspacedata └── xcshareddata │ ├── IDEWorkspaceChecks.plist │ ├── swiftpm │ └── Package.resolved │ └── xcschemes │ ├── Bookmarks iOS.xcscheme │ ├── Bookmarks macOS.xcscheme │ ├── BookmarksCore iOS.xcscheme │ └── BookmarksCore macOS.xcscheme ├── LICENSE ├── PRIVACY.md ├── README.md ├── core ├── Colors.xcassets │ ├── Contents.json │ └── ControlSecondaryBackground.colorset │ │ └── Contents.json ├── Package.swift ├── Sources │ └── BookmarksCore │ │ ├── Cache │ │ ├── FileImageCache.swift │ │ ├── ImageCache.swift │ │ └── MemoryImageCache.swift │ │ ├── Commands │ │ ├── AccountCommands.swift │ │ ├── ApplicationCommands.swift │ │ ├── BookmarkCommands.swift │ │ ├── BookmarkDestructiveCommands.swift │ │ ├── BookmarkEditCommands.swift │ │ ├── BookmarkInfoCommands.swift │ │ ├── BookmarkOpenCommands.swift │ │ ├── BookmarkShareCommands.swift │ │ ├── BookmarkTagCommands.swift │ │ ├── SectionCommands.swift │ │ ├── SidebarTagCommands.swift │ │ └── ViewCommands.swift │ │ ├── Common │ │ ├── ApplicationModel.swift │ │ ├── BookmarksError.swift │ │ ├── BookmarksSection.swift │ │ ├── Document.swift │ │ ├── DownloadManager.swift │ │ ├── Legal.swift │ │ ├── Localization.swift │ │ ├── Progress.swift │ │ ├── RemoteOperation.swift │ │ ├── SafeImage.swift │ │ ├── Settings.swift │ │ ├── SettingsKey.swift │ │ ├── Store.swift │ │ ├── ThumbnailManager.swift │ │ ├── Utilities.swift │ │ └── WebViewDownloader.swift │ │ ├── Extensions │ │ ├── Alert.swift │ │ ├── Array.swift │ │ ├── Color.swift │ │ ├── DispatchQueue.swift │ │ ├── Image.swift │ │ ├── Int.swift │ │ ├── MenuItem.swift │ │ ├── NSCoder.swift │ │ ├── Publisher.swift │ │ ├── SFSafariWindow.swift │ │ ├── Scene.swift │ │ ├── Statement.swift │ │ ├── String.swift │ │ ├── Toggle.swift │ │ ├── Trie+Bookmarks.swift │ │ ├── UIImage.swift │ │ ├── URL.swift │ │ ├── URLComponents.swift │ │ └── View.swift │ │ ├── Licenses │ │ ├── bookmarks-license │ │ ├── hashrainbow-license │ │ ├── interact-license │ │ ├── selectablecollectionview-license │ │ ├── sqlite-swift-license │ │ ├── swift-algorithm-club-license │ │ ├── swiftsoup-license │ │ ├── tfhpple-license │ │ └── wrappinghstack-license │ │ ├── Model │ │ ├── ApplicationState.swift │ │ ├── BrowserPreferene.swift │ │ ├── Confirmation.swift │ │ ├── InfoContentViewModel.swift │ │ ├── ItemViewModel.swift │ │ ├── LayoutMode.swift │ │ ├── SafariExtensionModel.swift │ │ ├── SceneState.swift │ │ ├── SectionViewModel.swift │ │ ├── SelectionScope.swift │ │ ├── Tab.swift │ │ ├── TagsContentViewModel.swift │ │ └── TokenViewModel.swift │ │ ├── Modifiers │ │ ├── Dismissable.swift │ │ ├── PresentsConfirmation.swift │ │ └── SceneActionHandler.swift │ │ ├── Pinboard │ │ ├── Boolean.swift │ │ ├── HTTPStatus.swift │ │ ├── Pinboard.swift │ │ ├── Post.swift │ │ ├── Posts.swift │ │ ├── Result.swift │ │ ├── Token.swift │ │ └── Update.swift │ │ ├── Resources │ │ └── en.lproj │ │ │ └── Localizable.strings │ │ ├── Scenes │ │ └── TagsWindow.swift │ │ ├── Store │ │ ├── Bookmark.swift │ │ ├── Database.swift │ │ ├── DatabasePublisher.swift │ │ ├── Expression.swift │ │ ├── QueryDescription.swift │ │ ├── Tag.swift │ │ └── TagsModel.swift │ │ ├── Styles │ │ └── FavoriteToggleStyle.swift │ │ ├── SwiftAlgorithmClub │ │ └── Trie.swift │ │ ├── Toolbars │ │ ├── AccountToolbar.swift │ │ ├── ApplicationToolbar.swift │ │ ├── LayoutToolbar.swift │ │ └── SelectionToolbar.swift │ │ ├── Utilities │ │ └── Synchronize.swift │ │ └── Views │ │ ├── AdvancedSettingsView.swift │ │ ├── BookmarkCell.swift │ │ ├── BorderedSelection.swift │ │ ├── ContentView.swift │ │ ├── FaviconImage.swift │ │ ├── InfoContentView.swift │ │ ├── ItemView.swift │ │ ├── LayoutPicker.swift │ │ ├── LeadingDivider.swift │ │ ├── LoadingView.swift │ │ ├── LogInView.swift │ │ ├── MacLogInView.swift │ │ ├── MacSectionGridView.swift │ │ ├── PhoneEditTagsView.swift │ │ ├── PhoneInfoView.swift │ │ ├── PhoneLogInView.swift │ │ ├── PhoneSafariView.swift │ │ ├── PhoneSectionGridView.swift │ │ ├── PhoneSettingsView.swift │ │ ├── PhoneTagsView.swift │ │ ├── PickerTextField.swift │ │ ├── SectionGridView.swift │ │ ├── SectionLink.swift │ │ ├── SectionTableView.swift │ │ ├── SectionView.swift │ │ ├── Sidebar.swift │ │ ├── SidebarContentView.swift │ │ ├── SidebarSettingsSection.swift │ │ ├── StatusView.swift │ │ ├── TagView.swift │ │ ├── TagsContentView.swift │ │ ├── TagsView.swift │ │ ├── TokenView.swift │ │ └── TrailingDivider.swift └── Tests │ └── BookmarksCoreTests │ ├── DatabaseTests.swift │ ├── QueryDescriptionTests.swift │ └── ThumbnailTests.swift ├── docs ├── .tool-versions ├── 404.html ├── CNAME ├── Gemfile ├── Gemfile.lock ├── _config.yml ├── _includes │ ├── footer.html │ └── navigation.html ├── _layouts │ └── default.html ├── css │ └── style.css ├── images │ ├── icon_128x128.png │ └── icon_128x128@2x.png ├── index.markdown └── privacy-policy │ └── index.markdown ├── graphics ├── Bookmarks.symbolic ├── Export │ ├── iOS │ │ ├── icon_1024x1024.png │ │ ├── icon_20x20.png │ │ ├── icon_20x20@2x.png │ │ ├── icon_20x20@3x.png │ │ ├── icon_29x29.png │ │ ├── icon_29x29@2x.png │ │ ├── icon_29x29@3x.png │ │ ├── icon_40x40.png │ │ ├── icon_40x40@2x.png │ │ ├── icon_40x40@3x.png │ │ ├── icon_60x60@2x.png │ │ ├── icon_60x60@3x.png │ │ ├── icon_76x76.png │ │ ├── icon_76x76@2x.png │ │ └── icon_83.5x83.5@2x.png │ ├── icon_1024x1024.png │ └── macOS.iconset │ │ ├── icon_128x128.png │ │ ├── icon_128x128@2x.png │ │ ├── icon_16x16.png │ │ ├── icon_16x16@2x.png │ │ ├── icon_256x256.png │ │ ├── icon_256x256@2x.png │ │ ├── icon_32x32.png │ │ ├── icon_32x32@2x.png │ │ ├── icon_512x512.png │ │ └── icon_512x512@2x.png ├── iOS icon.ai └── macOS icon.sketch ├── ios ├── Bookmarks Share Extension │ ├── Base.lproj │ │ ├── MainInterface.storyboard │ │ └── ShareViewController.xib │ ├── Bookmarks Share Extension.entitlements │ ├── Bookmarks_Share_Extension.entitlements │ ├── Info.plist │ ├── Model │ │ └── ShareExtensionModel.swift │ ├── ShareViewController.swift │ ├── Views │ │ ├── ContentView.swift │ │ ├── EditorView.swift │ │ └── RootView.swift │ └── icon.icns ├── Bookmarks-iOS.xcodeproj │ └── project.pbxproj ├── Bookmarks │ ├── Assets.xcassets │ │ ├── AppIcon.appiconset │ │ │ ├── Contents.json │ │ │ ├── icon_1024x1024.png │ │ │ ├── icon_20x20.png │ │ │ ├── icon_20x20@2x 1.png │ │ │ ├── icon_20x20@2x.png │ │ │ ├── icon_20x20@3x.png │ │ │ ├── icon_29x29.png │ │ │ ├── icon_29x29@2x 1.png │ │ │ ├── icon_29x29@2x.png │ │ │ ├── icon_29x29@3x.png │ │ │ ├── icon_40x40.png │ │ │ ├── icon_40x40@2x 1.png │ │ │ ├── icon_40x40@2x.png │ │ │ ├── icon_40x40@3x.png │ │ │ ├── icon_60x60@2x.png │ │ │ ├── icon_60x60@3x.png │ │ │ ├── icon_76x76.png │ │ │ ├── icon_76x76@2x.png │ │ │ └── icon_83.5x83.5@2x.png │ │ ├── Contents.json │ │ └── Icon.imageset │ │ │ ├── Contents.json │ │ │ └── icon_1024x1024.png │ ├── Base.lproj │ │ └── LaunchScreen.storyboard │ ├── Bookmarks-Bridging-Header.h │ ├── Bookmarks.entitlements │ ├── BookmarksApp.swift │ └── Info.plist ├── BookmarksTests │ ├── BookmarksTests.swift │ └── Info.plist ├── BookmarksUITests │ ├── BookmarksUITests.swift │ └── Info.plist ├── Common.xcconfig ├── Debug.xcconfig ├── ExportOptions.plist └── Release.xcconfig ├── macos ├── Bookmarks-macOS.xcodeproj │ └── project.pbxproj ├── Bookmarks │ ├── Assets.xcassets │ │ ├── AccentColor.colorset │ │ │ └── Contents.json │ │ ├── AppIcon.appiconset │ │ │ ├── Contents.json │ │ │ ├── icon_128x128.png │ │ │ ├── icon_128x128@2x.png │ │ │ ├── icon_16x16.png │ │ │ ├── icon_16x16@2x.png │ │ │ ├── icon_256x256.png │ │ │ ├── icon_256x256@2x.png │ │ │ ├── icon_32x32.png │ │ │ ├── icon_32x32@2x.png │ │ │ ├── icon_512x512.png │ │ │ └── icon_512x512@2x.png │ │ ├── Contents.json │ │ ├── Icon.imageset │ │ │ ├── Contents.json │ │ │ ├── icon_512x512.png │ │ │ └── icon_512x512@2x.png │ │ └── PinboardLogo.imageset │ │ │ ├── Artboard 1.png │ │ │ └── Contents.json │ ├── Bookmarks.entitlements │ ├── BookmarksApp.swift │ ├── Info.plist │ ├── Preview Content │ │ └── Preview Assets.xcassets │ │ │ └── Contents.json │ └── Views │ │ └── SettingsView.swift ├── BookmarksTests │ ├── BookmarksTests.swift │ └── Info.plist ├── BookmarksUITests │ ├── BookmarksUITests.swift │ └── Info.plist ├── Common.xcconfig ├── Debug.xcconfig ├── ExportOptions.plist ├── Release.xcconfig └── SafariExtension │ ├── Base.lproj │ └── SafariExtensionViewController.xib │ ├── ContentView.swift │ ├── HostedContentView.swift │ ├── Info.plist │ ├── Resources │ ├── ToolbarItemIcon.pdf │ └── script.js │ ├── SafariExtension.entitlements │ ├── SafariExtensionHandler.swift │ └── SafariExtensionViewController.swift ├── profiles ├── Bookmarks_App_Store_Profile.mobileprovision ├── Bookmarks_Mac_App_Store_Profile.provisionprofile ├── Bookmarks_Safari_Extension_Mac_App_Store_Profile.provisionprofile └── Bookmarks_Share_Extension_App_Store_Profile.mobileprovision ├── screenshot.png └── scripts ├── build-website.sh ├── build.sh ├── environment.sh ├── install-dependencies.sh ├── release-notes.markdown ├── release.sh └── update-release-notes.sh /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [jbmorley] 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | **.xcuserdatad 2 | *.p8 3 | .DS_Store 4 | .build 5 | .env 6 | .local 7 | .nova 8 | build 9 | temp 10 | xcuserdata 11 | 12 | /_site 13 | /build 14 | /docs/.jekyll-cache 15 | /docs/_site 16 | /docs/release-notes 17 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "ios/hpple"] 2 | path = dependencies/hpple 3 | url = git@github.com:jbmorley/hpple.git 4 | [submodule "interact"] 5 | path = dependencies/interact 6 | url = git@github.com:jbmorley/interact.git 7 | [submodule "scripts/changes"] 8 | path = scripts/changes 9 | url = https://github.com/jbmorley/changes.git 10 | [submodule "scripts/build-tools"] 11 | path = scripts/build-tools 12 | url = https://github.com/jbmorley/build-tools.git 13 | [submodule "diligence"] 14 | path = dependencies/diligence 15 | url = git@github.com:inseven/diligence.git 16 | [submodule "SQLite.swift"] 17 | path = dependencies/SQLite.swift 18 | url = git@github.com:jbmorley/SQLite.swift.git 19 | [submodule "SelectableCollectionView"] 20 | path = dependencies/SelectableCollectionView 21 | url = git@github.com:jbmorley/SelectableCollectionView.git 22 | -------------------------------------------------------------------------------- /Bookmarks.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Bookmarks.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Bookmarks.xcworkspace/xcshareddata/swiftpm/Package.resolved: -------------------------------------------------------------------------------- 1 | { 2 | "pins" : [ 3 | { 4 | "identity" : "cassowaryswift", 5 | "kind" : "remoteSourceControl", 6 | "location" : "https://github.com/tribalworldwidelondon/CassowarySwift.git", 7 | "state" : { 8 | "revision" : "7de8fee8331ad13eabb8de639fab0fde7a8f0d77", 9 | "version" : "2.0.1" 10 | } 11 | }, 12 | { 13 | "identity" : "hashrainbow", 14 | "kind" : "remoteSourceControl", 15 | "location" : "https://github.com/saramah/HashRainbow.git", 16 | "state" : { 17 | "branch" : "main", 18 | "revision" : "3eb3d2ce3b3fce35bcde312ed074a9c237d714ab" 19 | } 20 | }, 21 | { 22 | "identity" : "licensable", 23 | "kind" : "remoteSourceControl", 24 | "location" : "https://github.com/inseven/licensable", 25 | "state" : { 26 | "revision" : "a8ad62c6fde5aca29a47459b0687e580eee203dd", 27 | "version" : "0.0.13" 28 | } 29 | }, 30 | { 31 | "identity" : "swiftsoup", 32 | "kind" : "remoteSourceControl", 33 | "location" : "https://github.com/scinfu/SwiftSoup.git", 34 | "state" : { 35 | "revision" : "f83c097597094a04124eb6e0d1e894d24129af87", 36 | "version" : "2.7.0" 37 | } 38 | }, 39 | { 40 | "identity" : "wrappinghstack", 41 | "kind" : "remoteSourceControl", 42 | "location" : "https://github.com/ksemianov/WrappingHStack.git", 43 | "state" : { 44 | "branch" : "main", 45 | "revision" : "3300f68b6bf5f8a75ee7ca8a40f136a558053d10" 46 | } 47 | } 48 | ], 49 | "version" : 2 50 | } 51 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020-2025 Jason Morley 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /PRIVACY.md: -------------------------------------------------------------------------------- 1 | # Privacy Policy 2 | 3 | Bookmarks does not collect or store any personal data unless you have opted into crash reporting (details provided below). 4 | 5 | Should the policies outlined in this document change, we will make all reasonable efforts to inform you and provide mechanisms to opt-out. 6 | 7 | ## Crash Reporting 8 | 9 | If you have opted into crash reporting with Apple, we will occasionally receive crash logs from Apple which, ideally do not, but may contain personally identifiable information. Crash logs are stored privately and are kept confidential, and we will make all reasonable efforts to delete any found to contain personally identifiable information. 10 | 11 | ## Pinboard 12 | 13 | As a client for the Pinboard bookmarking service (https://pinboard.in), Bookmarks synchronizes data with Pinboard. Data stored in Pinboard is subject to their Privacy Policy (https://pinboard.in/privacy/). 14 | 15 | Bookmarks is not affiliated with Pinboard or Nine Fives Software and has no control over their Privacy Policy, or access to any information collected or stored as part of their service provision. 16 | 17 | ## Third-Party Websites 18 | 19 | Data processing necessary to select website thumbnails, index content for search, and enable other functionality, is performed entirely device-local within Bookmarks on iOS and macOS. Although Bookmarks does not utilize first- or third-party services when fetching this content, it is fetched from the URLs stored in your Pinboard account. Some of the authors of these websites may themselves employ tracking and analytics. Please refer to the privacy policies of these individual sites for more information. 20 | 21 | ## iCloud 22 | 23 | If you have enabled Apple iCloud services on the devices on which you run Bookmarks, application preferences and state may be stored in iCloud to facilitate a consistent experience across your devices. Data stored by Apple is subject to their Privacy Policy (https://www.apple.com/legal/privacy/). 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Bookmarks 2 | 3 | [![Build](https://github.com/inseven/bookmarks/actions/workflows/build.yaml/badge.svg?branch=main)](https://github.com/inseven/bookmarks/actions/workflows/build.yaml) 4 | 5 | [Pinboard](https://pinboard.in) client for iOS and macOS. 6 | 7 | ![Bookmarks screenshot](screenshot.png) 8 | 9 | ## Development 10 | 11 | Bookmarks follows the version numbering, build and signing conventions for InSeven Limited apps. Further details can be found [here](https://github.com/inseven/build-documentation). 12 | 13 | Use the `Bookmarks.xcworkspace` workspace with the Xcode GUI for local builds. Both the iOS and macOS debug builds are configured to use a local development account for signing. Release builds are configured for building under Continuous Integration via the 'scripts/build.sh' build script. These are run using GitHub Actions which ensures the correct environment variables are defined. 14 | 15 | ## Licensing 16 | 17 | Bookmarks is licensed under the MIT License (see [LICENSE](LICENSE)). 18 | -------------------------------------------------------------------------------- /core/Colors.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /core/Colors.xcassets/ControlSecondaryBackground.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "1.000", 9 | "green" : "1.000", 10 | "red" : "1.000" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "display-p3", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "50", 27 | "green" : "50", 28 | "red" : "50" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /core/Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version: 5.7 2 | 3 | import PackageDescription 4 | 5 | let package = Package( 6 | name: "BookmarksCore", 7 | defaultLocalization: "en", 8 | platforms: [ 9 | .iOS(.v16), 10 | .macOS(.v13), 11 | ], 12 | products: [ 13 | .library( 14 | name: "BookmarksCore", 15 | targets: ["BookmarksCore"]) 16 | ], 17 | dependencies: [ 18 | .package(path: "./../dependencies/diligence"), 19 | .package(path: "./../dependencies/interact"), 20 | .package(path: "./../dependencies/hpple"), 21 | .package(path: "./../dependencies/SQLite.swift"), 22 | .package(path: "./../dependencies/SelectableCollectionView"), 23 | .package(url: "https://github.com/ksemianov/WrappingHStack.git", branch: "main"), 24 | .package(url: "https://github.com/saramah/HashRainbow.git", branch: "main"), 25 | .package(url: "https://github.com/scinfu/SwiftSoup.git", from: "2.6.0"), 26 | ], 27 | targets: [ 28 | .target( 29 | name: "BookmarksCore", 30 | dependencies: [ 31 | .product(name: "Diligence", package: "Diligence"), 32 | .product(name: "Interact", package: "Interact"), 33 | .product(name: "SQLite", package: "SQLite.swift"), 34 | .product(name: "TFHpple", package: "hpple"), 35 | "WrappingHStack", 36 | "HashRainbow", 37 | "SwiftSoup", 38 | .product(name: "SelectableCollectionView", package: "SelectableCollectionView"), 39 | ], 40 | resources: [ 41 | .process("Licenses"), 42 | .process("Resources"), 43 | ]), 44 | .testTarget( 45 | name: "BookmarksCoreTests", 46 | dependencies: ["BookmarksCore"]), 47 | ] 48 | ) 49 | -------------------------------------------------------------------------------- /core/Sources/BookmarksCore/Cache/ImageCache.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Jason Morley 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | import Foundation 22 | 23 | #if os(iOS) 24 | import UIKit 25 | #endif 26 | 27 | enum ImageCacheError : Error { 28 | case notFound 29 | } 30 | 31 | public protocol ImageCache { 32 | 33 | func set(identifier: String, image: SafeImage, completion: @escaping (Result) -> Void) 34 | func get(identifier: String, completion: @escaping (Result) -> Void) 35 | func clear(completion: @escaping (Result) -> Void) 36 | 37 | } 38 | -------------------------------------------------------------------------------- /core/Sources/BookmarksCore/Commands/AccountCommands.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Jason Morley 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | import SwiftUI 22 | 23 | import Interact 24 | 25 | public struct AccountCommands: Commands { 26 | 27 | var applicationModel: ApplicationModel 28 | 29 | public init(applicationModel: ApplicationModel) { 30 | self.applicationModel = applicationModel 31 | } 32 | 33 | public var body: some Commands { 34 | 35 | CommandMenu("Account") { 36 | Button("Log Out...") { 37 | applicationModel.logout { _ in } 38 | } 39 | } 40 | 41 | CommandGroup(after: .newItem) { 42 | Divider() 43 | Button("Refresh") { 44 | await applicationModel.refresh() 45 | } 46 | .keyboardShortcut("r", modifiers: .command) 47 | } 48 | 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /core/Sources/BookmarksCore/Commands/ApplicationCommands.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Jason Morley 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | import SwiftUI 22 | 23 | public struct ApplicationCommands: Commands { 24 | 25 | @Environment(\.openWindow) var openWindow 26 | 27 | @FocusedBinding(\.sceneState) var sceneState 28 | 29 | public init() { 30 | 31 | } 32 | 33 | public var body: some Commands { 34 | CommandGroup(before: .appSettings) { 35 | Button { 36 | #if os(macOS) 37 | openWindow(id: TagsWindow.identifier) 38 | #else 39 | sceneState?.showTags() 40 | #endif 41 | } label: { 42 | Text("Tags...") 43 | } 44 | .keyboardShortcut("t", modifiers: [.command]) 45 | } 46 | 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /core/Sources/BookmarksCore/Commands/BookmarkCommands.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Jason Morley 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | import SwiftUI 22 | 23 | public struct BookmarkCommands: Commands { 24 | 25 | @FocusedObject var sectionViewModel: SectionViewModel? 26 | 27 | public init() { 28 | } 29 | 30 | public var body: some Commands { 31 | CommandMenu("Bookmark") { 32 | BookmarkInfoComands(sectionViewModel: sectionViewModel ?? SectionViewModel()) 33 | .trailingDivider() 34 | BookmarkOpenCommands(sectionViewModel: sectionViewModel ?? SectionViewModel()) 35 | .trailingDivider() 36 | BookmarkEditCommands(sectionViewModel: sectionViewModel ?? SectionViewModel()) 37 | .trailingDivider() 38 | BookmarkDesctructiveCommands(sectionViewModel: sectionViewModel ?? SectionViewModel()) 39 | .trailingDivider() 40 | BookmarkShareCommands(sectionViewModel: sectionViewModel ?? SectionViewModel()) 41 | .trailingDivider() 42 | BookmarkTagCommands(sectionViewModel: sectionViewModel ?? SectionViewModel()) 43 | } 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /core/Sources/BookmarksCore/Commands/BookmarkDestructiveCommands.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Jason Morley 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | import SwiftUI 22 | 23 | struct BookmarkDesctructiveCommands: View { 24 | 25 | @ObservedObject var sectionViewModel: SectionViewModel 26 | 27 | var body: some View { 28 | Button("Delete") { 29 | await sectionViewModel.delete(.selection) 30 | } 31 | .keyboardShortcut(.delete, modifiers: [.command]) 32 | .disabled(sectionViewModel.selection.isEmpty) 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /core/Sources/BookmarksCore/Commands/BookmarkEditCommands.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Jason Morley 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | import SwiftUI 22 | 23 | struct BookmarkEditCommands: View { 24 | 25 | @ObservedObject var sectionViewModel: SectionViewModel 26 | 27 | var body: some View { 28 | 29 | let bookmarks = sectionViewModel.bookmarks(.selection) 30 | let containsUnreadBookmark = bookmarks.containsUnreadBookmark 31 | let containsPublicBookmark = bookmarks.containsPublicBookmark 32 | 33 | Button(containsUnreadBookmark ? "Mark as Read" : "Mark as Unread") { 34 | await sectionViewModel.update(.selection, toRead: !containsUnreadBookmark) 35 | } 36 | .keyboardShortcut("u", modifiers: [.command, .shift]) 37 | .disabled(sectionViewModel.selection.isEmpty) 38 | 39 | Button(containsPublicBookmark ? "Make Private" : "Make Public") { 40 | await sectionViewModel.update(.selection, shared: !containsPublicBookmark) 41 | } 42 | .keyboardShortcut("p", modifiers: [.command, .shift]) 43 | .disabled(sectionViewModel.selection.isEmpty) 44 | 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /core/Sources/BookmarksCore/Commands/BookmarkInfoCommands.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Jason Morley 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | import SwiftUI 22 | 23 | struct BookmarkInfoComands: View { 24 | 25 | @Environment(\.openWindow) var openWindow 26 | 27 | @ObservedObject var sectionViewModel: SectionViewModel 28 | 29 | var body: some View { 30 | 31 | Button(LocalizedString("BOOKMARK_MENU_TITLE_GET_INFO")) { 32 | for id in sectionViewModel.selection { 33 | openWindow(value: id) 34 | } 35 | } 36 | .disabled(sectionViewModel.selection.isEmpty) 37 | .keyboardShortcut("i", modifiers: [.command]) 38 | 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /core/Sources/BookmarksCore/Commands/BookmarkShareCommands.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Jason Morley 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | import SwiftUI 22 | 23 | struct BookmarkShareCommands: View { 24 | 25 | @ObservedObject var sectionViewModel: SectionViewModel 26 | 27 | var body: some View { 28 | Button("Copy") { 29 | sectionViewModel.copy(.selection) 30 | } 31 | .keyboardShortcut("c", modifiers: [.command]) 32 | .disabled(sectionViewModel.selection.isEmpty) 33 | 34 | Button("Copy Tags") { 35 | sectionViewModel.copyTags(.selection) 36 | } 37 | .keyboardShortcut("c", modifiers: [.command, .shift]) 38 | .disabled(sectionViewModel.selection.isEmpty) 39 | 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /core/Sources/BookmarksCore/Commands/BookmarkTagCommands.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Jason Morley 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | import SwiftUI 22 | 23 | struct BookmarkTagCommands: View { 24 | 25 | @FocusedBinding(\.sceneState) var sceneState 26 | 27 | @ObservedObject var sectionViewModel: SectionViewModel 28 | 29 | var body: some View { 30 | Menu("Tags") { 31 | 32 | ForEach(Array(sectionViewModel.selectionTags).sorted()) { tag in 33 | Button(tag) { 34 | sceneState?.revealTag(tag) 35 | } 36 | .disabled(sceneState == nil) 37 | } 38 | 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /core/Sources/BookmarksCore/Commands/SectionCommands.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Jason Morley 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | import SwiftUI 22 | 23 | public struct SectionCommands: Commands { 24 | 25 | @ObservedObject var settings: Settings 26 | 27 | @FocusedBinding(\.sceneState) var sceneState: SceneState? 28 | 29 | static func keyEquivalent(_ value: Int) -> KeyEquivalent { 30 | return KeyEquivalent(String(value).first!) 31 | } 32 | 33 | public init(settings: Settings) { 34 | self.settings = settings 35 | } 36 | 37 | public var body: some Commands { 38 | CommandMenu("Go") { 39 | ForEach(Array(settings.librarySections.enumerated()), id: \.element.id) { index, librarySection in 40 | Button(librarySection.section.navigationTitle) { 41 | sceneState?.section = librarySection.section 42 | } 43 | .keyboardShortcut(Self.keyEquivalent(index + 1), modifiers: .command) 44 | .disabled(sceneState == nil) 45 | } 46 | } 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /core/Sources/BookmarksCore/Commands/SidebarTagCommands.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Jason Morley 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | import SwiftUI 22 | 23 | public struct SidebarTagCommands: View { 24 | 25 | @EnvironmentObject var applicationModel: ApplicationModel 26 | 27 | let tag: String 28 | 29 | public var body: some View { 30 | if applicationModel.isFavorite(tag) { 31 | Button { 32 | applicationModel.removeFavorite(tag) 33 | } label: { 34 | Label("Remove from Favorites", systemImage: "star.slash") 35 | } 36 | } else { 37 | Button { 38 | applicationModel.addFavorite(tag) 39 | } label: { 40 | Label("Add to Favorites", systemImage: "star") 41 | } 42 | } 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /core/Sources/BookmarksCore/Common/Localization.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Jason Morley 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | import Foundation 22 | 23 | public func Localized(_ layoutMode: LayoutMode) -> String { 24 | switch layoutMode { 25 | case .grid: 26 | return "Grid" 27 | case .table: 28 | return "List" 29 | } 30 | } 31 | 32 | func LocalizedString(_ key: String, comment: String? = nil) -> String { 33 | return NSLocalizedString(key, bundle: .module, comment: comment ?? "") 34 | } 35 | -------------------------------------------------------------------------------- /core/Sources/BookmarksCore/Common/Progress.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Jason Morley 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | import Foundation 22 | 23 | public enum Progress { 24 | 25 | case idle 26 | case active 27 | case value(Float) 28 | case done(Date) 29 | case failure(Error) 30 | 31 | var isRunning: Bool { 32 | switch self { 33 | case .idle, .done, .failure: 34 | return false 35 | case .active, .value: 36 | return true 37 | } 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /core/Sources/BookmarksCore/Common/SafeImage.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Jason Morley 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | import Foundation 22 | 23 | #if os(iOS) 24 | 25 | import UIKit 26 | 27 | public typealias SafeImage = UIImage 28 | 29 | #else 30 | 31 | import AppKit 32 | 33 | public typealias SafeImage = NSImage 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /core/Sources/BookmarksCore/Extensions/Alert.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Jason Morley 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | import SwiftUI 22 | 23 | public extension Alert { 24 | 25 | init(error: Error?) { 26 | self.init(title: Text("Error"), 27 | message: Text(error?.localizedDescription ?? ""), 28 | dismissButton: .default(Text("OK"))) 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /core/Sources/BookmarksCore/Extensions/DispatchQueue.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Jason Morley 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | import Foundation 22 | 23 | extension DispatchQueue { 24 | 25 | public func asyncClosure(_ closure: @escaping () -> Void) -> () -> Void { 26 | return { self.async { closure() } } 27 | } 28 | 29 | public func asyncClosure(_ closure: (() -> Void)?) -> (() -> Void)? { 30 | guard let closure = closure else { 31 | return nil 32 | } 33 | return { self.async { closure() } } 34 | } 35 | 36 | public func asyncClosure(_ closure: @escaping (T) -> Void) -> (T) -> Void { 37 | return { i in self.async { closure(i) } } 38 | } 39 | 40 | public func asyncClosure(_ closure: ((T) -> Void)?) -> ((T) -> Void)? { 41 | guard let closure = closure else { 42 | return nil 43 | } 44 | return { i in self.async { closure(i) } } 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /core/Sources/BookmarksCore/Extensions/Image.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Jason Morley 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | import SwiftUI 22 | 23 | extension Image { 24 | 25 | init(safeImage: SafeImage) { 26 | #if os(iOS) 27 | self.init(uiImage: safeImage) 28 | #else 29 | self.init(nsImage: safeImage) 30 | #endif 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /core/Sources/BookmarksCore/Extensions/Int.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Jason Morley 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | import SwiftUI 22 | 23 | extension Int: Identifiable { 24 | 25 | public var id: Self { self } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /core/Sources/BookmarksCore/Extensions/MenuItem.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Jason Morley 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | import Foundation 22 | import SwiftUI 23 | 24 | import Interact 25 | 26 | import SelectableCollectionView 27 | 28 | extension MenuItem { 29 | 30 | init(_ title: String, systemImage: String? = nil, role: ButtonRole? = nil, action: @escaping () async -> Void) { 31 | self.init(title, systemImage: systemImage, role: role) { 32 | Task { 33 | await action() 34 | } 35 | } 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /core/Sources/BookmarksCore/Extensions/NSCoder.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Jason Morley 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | import Foundation 22 | 23 | extension NSCoder { 24 | 25 | public func decodeString(forKey key: String) -> String? { 26 | return decodeObject(of: NSString.self, forKey: key) as String? 27 | } 28 | 29 | public func decodeUrl(forKey key: String) -> URL? { 30 | return decodeObject(of: NSURL.self, forKey: key) as URL? 31 | } 32 | 33 | public func decodeDate(forKey key: String) -> Date? { 34 | return decodeObject(of: NSDate.self, forKey: key) as Date? 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /core/Sources/BookmarksCore/Extensions/Publisher.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Jason Morley 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | import Combine 22 | 23 | extension Publisher { 24 | 25 | public func asyncMap(_ transform: @escaping (Output) async -> T) -> Publishers.FlatMap, Self> { 26 | flatMap { value in 27 | Future { promise in 28 | Task { 29 | let output = await transform(value) 30 | promise(.success(output)) 31 | } 32 | } 33 | } 34 | } 35 | 36 | public func asyncMap(_ transform: @escaping (Output) async throws -> T) -> Publishers.FlatMap, Self> { 37 | flatMap { value in 38 | Future { promise in 39 | Task { 40 | do { 41 | let output = try await transform(value) 42 | promise(.success(output)) 43 | } catch { 44 | promise(.failure(error)) 45 | } 46 | } 47 | } 48 | } 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /core/Sources/BookmarksCore/Extensions/Scene.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Jason Morley 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | import SwiftUI 22 | 23 | extension Scene { 24 | 25 | public func commonCommands(applicationModel: ApplicationModel) -> some Scene { 26 | commands { 27 | 28 | SidebarCommands() 29 | ToolbarCommands() 30 | 31 | AccountCommands(applicationModel: applicationModel) 32 | ApplicationCommands() 33 | SectionCommands(settings: applicationModel.settings) 34 | ViewCommands() 35 | BookmarkCommands() 36 | 37 | } 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /core/Sources/BookmarksCore/Extensions/Toggle.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Jason Morley 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | import SwiftUI 22 | 23 | extension Toggle where Label == EmptyView { 24 | 25 | init(isOn: Binding) { 26 | self.init(isOn: isOn) { 27 | EmptyView() 28 | } 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /core/Sources/BookmarksCore/Extensions/Trie+Bookmarks.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Jason Morley 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | import Foundation 22 | 23 | extension Trie { 24 | 25 | public convenience init(words: C) where C.Element == String { 26 | self.init() 27 | for word in words { 28 | self.insert(word: word) 29 | } 30 | } 31 | 32 | public func suggestions(for prefix: String, count: Int) -> [String] { 33 | return findWordsWithPrefix(prefix: prefix) 34 | .sorted() 35 | .prefix(count) 36 | .sorted() 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /core/Sources/BookmarksCore/Extensions/URLComponents.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Jason Morley 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | import Foundation 22 | 23 | extension URLComponents { 24 | 25 | init?(unsafeString: String) { 26 | self.init(string: unsafeString.replacingOccurrences(of: " ", with: "%20")) 27 | } 28 | 29 | public var safeUrl: URL { 30 | get throws { 31 | guard let url = self.url else { 32 | throw BookmarksError.invalidURLComponents(self) 33 | } 34 | return url 35 | } 36 | } 37 | 38 | func queryItem(_ name: String) -> String? { 39 | return queryItems? 40 | .first(where: { $0.name == name })? 41 | .value 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /core/Sources/BookmarksCore/Extensions/View.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Jason Morley 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | import SwiftUI 22 | 23 | extension View { 24 | 25 | #if os(iOS) 26 | 27 | func onDeleteCommand(perform: @escaping () -> Void) -> some View { 28 | return self 29 | } 30 | 31 | #endif 32 | 33 | } 34 | -------------------------------------------------------------------------------- /core/Sources/BookmarksCore/Licenses/bookmarks-license: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020-2025 Jason Morley 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /core/Sources/BookmarksCore/Licenses/hashrainbow-license: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Sarah Barbour 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /core/Sources/BookmarksCore/Licenses/interact-license: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020-2021 InSeven Limited 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /core/Sources/BookmarksCore/Licenses/selectablecollectionview-license: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Jason Morley 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /core/Sources/BookmarksCore/Licenses/sqlite-swift-license: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014-2015 Stephen Celis () 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /core/Sources/BookmarksCore/Licenses/swift-algorithm-club-license: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Matthijs Hollemans and contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /core/Sources/BookmarksCore/Licenses/swiftsoup-license: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Nabil Chatbi 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /core/Sources/BookmarksCore/Licenses/tfhpple-license: -------------------------------------------------------------------------------- 1 | Copyright (c) 2009 Topfunky Corporation, http://topfunky.com 2 | 3 | MIT LICENSE 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /core/Sources/BookmarksCore/Licenses/wrappinghstack-license: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Konstantin Semianov 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /core/Sources/BookmarksCore/Model/ApplicationState.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Jason Morley 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | import Foundation 22 | 23 | public enum ApplicationState: Identifiable { 24 | 25 | case logIn 26 | 27 | public var id: String { 28 | switch self { 29 | case .logIn: 30 | return "logIn" 31 | } 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /core/Sources/BookmarksCore/Model/BrowserPreferene.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Jason Morley 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | import Foundation 22 | 23 | enum BrowserPreference { 24 | case app 25 | case system 26 | } 27 | -------------------------------------------------------------------------------- /core/Sources/BookmarksCore/Model/Confirmation.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Jason Morley 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | import SwiftUI 22 | 23 | struct Confirmation { 24 | 25 | let title: String 26 | let role: ButtonRole? 27 | let actionTitle: String? 28 | let message: String? 29 | let action: () -> Void 30 | 31 | init(_ title: String, 32 | role: ButtonRole? = nil, 33 | actionTitle: String = "OK", 34 | message: String? = nil, 35 | action: @escaping () -> Void) { 36 | self.title = title 37 | self.role = role 38 | self.actionTitle = actionTitle 39 | self.message = message 40 | self.action = action 41 | } 42 | 43 | init(_ title: String, 44 | role: ButtonRole? = nil, 45 | actionTitle: String = "OK", 46 | message: String? = nil, 47 | action: @escaping () async -> Void) { 48 | self.init(title, role: role, actionTitle: actionTitle, message: message) { 49 | Task { 50 | await action() 51 | } 52 | } 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /core/Sources/BookmarksCore/Model/LayoutMode.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Jason Morley 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | import SwiftUI 22 | 23 | public enum LayoutMode: String, CaseIterable, Identifiable { 24 | 25 | public var id: Self { self } 26 | 27 | case grid 28 | case table 29 | 30 | public var systemImage: String { 31 | switch self { 32 | case .grid: 33 | return "square.grid.2x2" 34 | case .table: 35 | return "list.bullet" 36 | } 37 | } 38 | 39 | var keyboardShortcut: KeyEquivalent { 40 | switch self { 41 | case .grid: 42 | return "j" 43 | case .table: 44 | return "k" 45 | } 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /core/Sources/BookmarksCore/Model/SelectionScope.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Jason Morley 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | import Foundation 22 | 23 | public enum SelectionScope { 24 | 25 | case selection 26 | case items(Set) 27 | 28 | } 29 | -------------------------------------------------------------------------------- /core/Sources/BookmarksCore/Model/Tab.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Jason Morley 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | import SwiftUI 22 | 23 | public struct Tab: Identifiable { 24 | 25 | public let id = UUID() 26 | 27 | public let url: URL 28 | public let title: String 29 | public let image: Image 30 | 31 | public init(url: URL, title: String, image: Image) { 32 | self.url = url 33 | self.title = title 34 | self.image = image 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /core/Sources/BookmarksCore/Modifiers/PresentsConfirmation.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Jason Morley 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | import SwiftUI 22 | 23 | struct PresentsConfirmation: ViewModifier { 24 | 25 | @Binding var confirmation: Confirmation? 26 | 27 | init(_ confirmation: Binding) { 28 | _confirmation = confirmation 29 | } 30 | 31 | func body(content: Content) -> some View { 32 | content 33 | .confirmationDialog(confirmation?.title ?? "Confirm", 34 | isPresented: $confirmation.bool(), 35 | titleVisibility: .visible) { 36 | Button(confirmation?.actionTitle ?? "OK", role: confirmation?.role) { 37 | confirmation?.action() 38 | } 39 | } message: { 40 | if let message = confirmation?.message { 41 | Text(message) 42 | } 43 | } 44 | } 45 | 46 | } 47 | 48 | extension View { 49 | 50 | func presents(_ confirmation: Binding) -> some View { 51 | modifier(PresentsConfirmation(confirmation)) 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /core/Sources/BookmarksCore/Modifiers/SceneActionHandler.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Jason Morley 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | import SwiftUI 22 | 23 | struct SceneActionHandler: ViewModifier { 24 | 25 | @Binding var sceneState: SceneState 26 | 27 | func body(content: Content) -> some View { 28 | content 29 | .handlesExternalEvents(preferring: ["/open"], allowing: []) 30 | .onOpenURL { url in 31 | sceneState.handleURL(url) 32 | } 33 | } 34 | 35 | } 36 | 37 | extension View { 38 | 39 | func handlesSceneActions(_ sceneState: Binding) -> some View { 40 | return modifier(SceneActionHandler(sceneState: sceneState)) 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /core/Sources/BookmarksCore/Pinboard/Boolean.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Jason Morley 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | import Foundation 22 | 23 | public enum Boolean: String, Codable { 24 | case yes = "yes" 25 | case no = "no" 26 | } 27 | -------------------------------------------------------------------------------- /core/Sources/BookmarksCore/Pinboard/Posts.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Jason Morley 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | import Foundation 22 | 23 | extension Pinboard { 24 | 25 | public struct Posts: Codable { 26 | 27 | public let date: Date 28 | public let user: String 29 | public let posts: [Post] 30 | 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /core/Sources/BookmarksCore/Pinboard/Result.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Jason Morley 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | import Foundation 22 | 23 | extension Pinboard { 24 | 25 | public struct Result: Codable { 26 | 27 | private enum CodingKeys: String, CodingKey { 28 | case resultCode = "result_code" 29 | } 30 | 31 | let resultCode: String 32 | 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /core/Sources/BookmarksCore/Pinboard/Token.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Jason Morley 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | import Foundation 22 | 23 | extension Pinboard { 24 | 25 | public struct Token: Codable { 26 | 27 | public let result: String 28 | 29 | public enum CodingKeys: String, CodingKey { 30 | case result = "result" 31 | } 32 | 33 | public init(from decoder: Decoder) throws { 34 | let container = try decoder.container(keyedBy: CodingKeys.self) 35 | self.result = try container.decode(String.self, forKey: .result) 36 | } 37 | 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /core/Sources/BookmarksCore/Pinboard/Update.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Jason Morley 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | import Foundation 22 | 23 | extension Pinboard { 24 | 25 | public struct Update: Codable { 26 | 27 | public let updateTime: Date 28 | 29 | public enum CodingKeys: String, CodingKey { 30 | case updateTime = "update_time" 31 | } 32 | 33 | public init(from decoder: Decoder) throws { 34 | let container = try decoder.container(keyedBy: CodingKeys.self) 35 | let updateTimeString = try container.decode(String.self, forKey: .updateTime) 36 | guard let updateTime = ISO8601DateFormatter.init().date(from: updateTimeString) else { 37 | throw BookmarksError.invalidResponse 38 | } 39 | self.updateTime = updateTime 40 | } 41 | 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /core/Sources/BookmarksCore/Resources/en.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Jason Morley 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | "BOOKMARK_MENU_TITLE_GET_INFO" = "Get Info"; 22 | "BOOKMARK_MENU_TITLE_OPEN_IN_APP" = "Open in App"; 23 | "BOOKMARK_MENU_TITLE_OPEN_IN_BROWSER" = "Open in Browser"; 24 | "BOOKMARK_MENU_TITLE_OPEN" = "Open"; 25 | "BOOKMARK_MENU_TITLE_PREVIEW" = "Preview"; 26 | "BOOKMARK_MENU_TITLE_VIEW_ON_INTERNET_ARCHIVE" = "View on Internet Archive"; 27 | -------------------------------------------------------------------------------- /core/Sources/BookmarksCore/Scenes/TagsWindow.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Jason Morley 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | import SwiftUI 22 | 23 | #if os(macOS) 24 | 25 | public struct TagsWindow: Scene { 26 | 27 | static let identifier = "tags" 28 | 29 | private let applicationModel: ApplicationModel 30 | 31 | public init(applicationModel: ApplicationModel) { 32 | self.applicationModel = applicationModel 33 | } 34 | 35 | public var body: some Scene { 36 | Window("Tags", id: TagsWindow.identifier) { 37 | TagsContentView(applicationModel: applicationModel) 38 | .environmentObject(applicationModel) 39 | .environmentObject(applicationModel.settings) 40 | } 41 | } 42 | 43 | } 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /core/Sources/BookmarksCore/Store/Expression.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Jason Morley 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | import SQLite 22 | 23 | // Unfortunately Foundation has now introduced `Expression` so we need to ensure the one from SQLite takes precedence. 24 | typealias Expression = SQLite.Expression 25 | -------------------------------------------------------------------------------- /core/Sources/BookmarksCore/Store/Tag.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Jason Morley 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | import Foundation 22 | 23 | extension Database { 24 | 25 | public struct Tag: Identifiable { 26 | 27 | public var id: String { name } 28 | 29 | public let name: String 30 | public let count: Int 31 | 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /core/Sources/BookmarksCore/Styles/FavoriteToggleStyle.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Jason Morley 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | import SwiftUI 22 | 23 | struct FavoriteToggleStyle: ToggleStyle { 24 | 25 | func makeBody(configuration: Configuration) -> some View { 26 | Button { 27 | configuration.isOn.toggle() 28 | } label: { 29 | if configuration.isOn { 30 | Image(systemName: "star.fill") 31 | } else { 32 | Image(systemName: "star") 33 | } 34 | } 35 | } 36 | 37 | } 38 | 39 | extension ToggleStyle where Self == FavoriteToggleStyle { 40 | 41 | static var favorite: Self { 42 | return FavoriteToggleStyle() 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /core/Sources/BookmarksCore/Toolbars/AccountToolbar.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Jason Morley 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | import SwiftUI 22 | 23 | import Interact 24 | 25 | public struct AccountToolbar: CustomizableToolbarContent { 26 | 27 | @EnvironmentObject var applicationModel: ApplicationModel 28 | 29 | public init() { 30 | 31 | } 32 | 33 | public var body: some CustomizableToolbarContent { 34 | 35 | ToolbarItem(id: "refresh") { 36 | Button { 37 | await applicationModel.refresh() 38 | } label: { 39 | Label("Refresh", systemImage: "arrow.clockwise") 40 | } 41 | .help("Refresh") 42 | .disabled(applicationModel.progress.isRunning) 43 | } 44 | 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /core/Sources/BookmarksCore/Toolbars/ApplicationToolbar.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Jason Morley 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | import SwiftUI 22 | 23 | #if os(macOS) 24 | 25 | public struct ApplicationToolbar: CustomizableToolbarContent { 26 | 27 | @Environment(\.openWindow) var openWindow 28 | 29 | public init() { 30 | 31 | } 32 | 33 | public var body: some CustomizableToolbarContent { 34 | 35 | ToolbarItem(id: "tags") { 36 | Button { 37 | openWindow(id: TagsWindow.identifier) 38 | } label: { 39 | Label("Tags", systemImage: "tag") 40 | } 41 | } 42 | 43 | } 44 | 45 | } 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /core/Sources/BookmarksCore/Toolbars/LayoutToolbar.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Jason Morley 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | import SwiftUI 22 | 23 | public struct LayoutToolbar: CustomizableToolbarContent { 24 | 25 | @FocusedObject var sectionViewModel: SectionViewModel? 26 | 27 | public init() { 28 | 29 | } 30 | 31 | public var body: some CustomizableToolbarContent { 32 | ToolbarItem(id: "layout-mode") { 33 | LayoutPicker() 34 | .environmentObject(sectionViewModel ?? SectionViewModel()) 35 | } 36 | 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /core/Sources/BookmarksCore/Utilities/Synchronize.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Jason Morley 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | import Foundation 22 | 23 | // TODO: It would be much more elegant to use a concurrent box here. 24 | fileprivate class Box { 25 | var contents: T 26 | 27 | init(contents: T) { 28 | self.contents = contents 29 | } 30 | } 31 | 32 | enum SynchronizeError: Error { 33 | case unknown 34 | } 35 | 36 | func Synchronize(perform: @escaping () async throws -> T) -> Result { 37 | let sem = DispatchSemaphore(value: 0) 38 | let box = Box>(contents: .failure(SynchronizeError.unknown)) 39 | Task { 40 | do { 41 | let result = try await perform() 42 | box.contents = .success(result) 43 | sem.signal() 44 | } catch { 45 | box.contents = .failure(error) 46 | sem.signal() 47 | } 48 | } 49 | sem.wait() 50 | return box.contents 51 | } 52 | -------------------------------------------------------------------------------- /core/Sources/BookmarksCore/Views/BorderedSelection.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Jason Morley 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | #if os(macOS) 22 | 23 | import SwiftUI 24 | 25 | import SelectableCollectionView 26 | 27 | public struct BorderedSelection: ViewModifier { 28 | 29 | @Environment(\.isSelected) var isSelected 30 | @Environment(\.highlightState) var highlightState 31 | 32 | var color: Color { 33 | return isSelected || highlightState == .forSelection ? Color.accentColor : Color.clear 34 | } 35 | 36 | public init() { 37 | 38 | } 39 | 40 | public func body(content: Content) -> some View { 41 | content 42 | .overlay( 43 | RoundedRectangle(cornerRadius: 13) 44 | .stroke(color, lineWidth: 4)) 45 | } 46 | 47 | } 48 | 49 | #endif 50 | -------------------------------------------------------------------------------- /core/Sources/BookmarksCore/Views/LayoutPicker.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Jason Morley 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | import SwiftUI 22 | 23 | public struct LayoutPicker: View { 24 | 25 | @EnvironmentObject var sectionViewModel: SectionViewModel 26 | 27 | public init() { 28 | 29 | } 30 | 31 | public var body: some View { 32 | Picker(selection: $sectionViewModel.layoutMode) { 33 | ForEach(LayoutMode.allCases) { layoutMode in 34 | Label(Localized(layoutMode), systemImage: layoutMode.systemImage) 35 | .help(Localized(layoutMode)) 36 | .tag(layoutMode) 37 | } 38 | } label: { 39 | Text("Layout") 40 | } 41 | .pickerStyle(.inline) 42 | .disabled(sectionViewModel.isPlaceholder) 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /core/Sources/BookmarksCore/Views/LeadingDivider.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Jason Morley 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | import SwiftUI 22 | 23 | struct LeadingDivider: ViewModifier { 24 | 25 | func body(content: Content) -> some View { 26 | Divider() 27 | content 28 | } 29 | 30 | } 31 | 32 | extension View { 33 | 34 | public func leadingDivider() -> some View { 35 | modifier(LeadingDivider()) 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /core/Sources/BookmarksCore/Views/LoadingView.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Jason Morley 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | import SwiftUI 22 | 23 | import Interact 24 | 25 | public struct LoadingView: View { 26 | 27 | public init () { 28 | 29 | } 30 | 31 | public var body: some View { 32 | PlaceholderView { 33 | ProgressView() 34 | .progressViewStyle(.circular) 35 | .controlSize(.large) 36 | } 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /core/Sources/BookmarksCore/Views/LogInView.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Jason Morley 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | import Foundation 22 | 23 | #if os(macOS) 24 | typealias LogInView = MacLogInView 25 | #else 26 | typealias LogInView = PhoneLogInView 27 | #endif 28 | -------------------------------------------------------------------------------- /core/Sources/BookmarksCore/Views/PhoneInfoView.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Jason Morley 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | #if os(iOS) 22 | 23 | import SwiftUI 24 | 25 | public struct PhoneInfoView: View { 26 | 27 | @Environment(\.dismiss) var dismiss 28 | @EnvironmentObject var applicationModel: ApplicationModel 29 | 30 | let id: Bookmark.ID 31 | 32 | public var body: some View { 33 | NavigationStack { 34 | InfoContentView(applicationModel: applicationModel, id: id) 35 | .environmentObject(applicationModel.tagsModel) 36 | .navigationBarTitleDisplayMode(.inline) 37 | .dismissable(.close) 38 | } 39 | } 40 | 41 | } 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /core/Sources/BookmarksCore/Views/PhoneSafariView.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Jason Morley 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | #if os(iOS) 22 | 23 | import SafariServices 24 | import SwiftUI 25 | 26 | public struct PhoneSafariView: UIViewControllerRepresentable { 27 | 28 | let url: URL 29 | 30 | public init(url: URL) { 31 | self.url = url 32 | } 33 | 34 | public func makeUIViewController(context: Context) -> some UIViewController { 35 | return SFSafariViewController(url: url) 36 | } 37 | 38 | public func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) { 39 | 40 | } 41 | 42 | } 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /core/Sources/BookmarksCore/Views/PhoneSectionGridView.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Jason Morley 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | #if os(iOS) 22 | 23 | import SwiftUI 24 | 25 | struct PhoneSectionGridView: View { 26 | 27 | @EnvironmentObject var applicationModel: ApplicationModel 28 | @EnvironmentObject var settings: Settings 29 | @EnvironmentObject var sectionViewModel: SectionViewModel 30 | 31 | var body: some View { 32 | ScrollView { 33 | LazyVGrid(columns: [GridItem(.adaptive(minimum: 160), spacing: 16)], spacing: 16) { 34 | ForEach(sectionViewModel.bookmarks) { bookmark in 35 | BookmarkCell(applicationModel: applicationModel, bookmark: bookmark) 36 | .aspectRatio(8/9, contentMode: .fit) 37 | .onTapGesture { 38 | sectionViewModel.open(.items([bookmark.id]), browser: settings.browser) 39 | } 40 | .contextMenu { 41 | sectionViewModel.contextMenu([bookmark.id]) 42 | } 43 | } 44 | } 45 | .padding() 46 | } 47 | } 48 | 49 | } 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /core/Sources/BookmarksCore/Views/SectionGridView.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Jason Morley 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | import Foundation 22 | 23 | #if os(macOS) 24 | typealias SectionGridView = MacSectionGridView 25 | #else 26 | typealias SectionGridView = PhoneSectionGridView 27 | #endif 28 | -------------------------------------------------------------------------------- /core/Sources/BookmarksCore/Views/SectionLink.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Jason Morley 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | import SwiftUI 22 | 23 | import Interact 24 | 25 | public struct SectionLink: View { 26 | 27 | let section: BookmarksSection 28 | 29 | public var body: some View { 30 | Label { 31 | Text(section.sidebarTitle) 32 | } icon: { 33 | Image(systemName: section.systemImage) 34 | } 35 | .safeNavigationLink(section) 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /core/Sources/BookmarksCore/Views/SidebarSettingsSection.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Jason Morley 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | import SwiftUI 22 | 23 | public struct SidebarSettingsSection: View { 24 | 25 | @ObservedObject var settings: Settings 26 | 27 | public init(settings: Settings) { 28 | self.settings = settings 29 | } 30 | 31 | public var body: some View { 32 | Section("Sidebar") { 33 | Picker("Top Tags", selection: $settings.topTagsCount) { 34 | ForEach(Array(stride(from: 0, to: 25, by: 5))) { value in 35 | Text(value == 0 ? "Off" : "\(value)") 36 | .tag(value) 37 | } 38 | } 39 | } 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /core/Sources/BookmarksCore/Views/StatusView.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Jason Morley 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | import SwiftUI 22 | 23 | public struct StatusView: View { 24 | 25 | @EnvironmentObject var applicationModel: ApplicationModel 26 | 27 | public init() { 28 | 29 | } 30 | 31 | public var body: some View { 32 | VStack { 33 | switch applicationModel.progress { 34 | case .idle: 35 | Text("Never updated") 36 | case .active: 37 | Text("Updating...") 38 | case .value(let progress): 39 | ProgressView(value: progress) 40 | .progressViewStyle(.linear) 41 | .frame(width: 100) 42 | case .done(let date): 43 | TimelineView(.periodic(from: .now, by: 60)) { timeline in 44 | Text("Updated \(date.formatted(.relative(presentation: .named)))") 45 | } 46 | case .failure(let error): 47 | Label(error.localizedDescription, systemImage: "exclamationmark.triangle.fill") 48 | } 49 | } 50 | .font(.footnote) 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /core/Sources/BookmarksCore/Views/TagView.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Jason Morley 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | import SwiftUI 22 | 23 | public struct TagView: View { 24 | 25 | struct LayoutMetrics { 26 | static let cornerRadius = 4.0 27 | } 28 | 29 | let text: String 30 | let color: Color 31 | 32 | public init(_ text: String) { 33 | self.text = text 34 | self.color = text.color() 35 | } 36 | 37 | public var body: some View { 38 | HStack(spacing: 0) { 39 | Text(text) 40 | .lineLimit(1) 41 | .padding([.top, .bottom], 2) 42 | .padding([.leading, .trailing], 6) 43 | } 44 | .padding(2) 45 | .foregroundColor(color) 46 | .background(color 47 | .opacity(0.3) 48 | .background(.background)) 49 | .clipShape(RoundedRectangle(cornerRadius: LayoutMetrics.cornerRadius)) 50 | .fixedSize(horizontal: true, vertical: true) 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /core/Sources/BookmarksCore/Views/TagsView.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Jason Morley 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | import SwiftUI 22 | 23 | import WrappingHStack 24 | 25 | struct TagsView: View { 26 | 27 | let tags: [String] 28 | let wraps: Bool 29 | 30 | init(_ tags: Set, wraps: Bool = true) { 31 | self.tags = tags.sorted() 32 | self.wraps = wraps 33 | } 34 | 35 | var body: some View { 36 | HStack { 37 | if wraps { 38 | if !tags.isEmpty { 39 | WrappingHStack(alignment: .leading) { 40 | ForEach(tags) { tag in 41 | TagView(tag) 42 | } 43 | } 44 | } else { 45 | EmptyView() 46 | } 47 | } else { 48 | ForEach(tags) { tag in 49 | TagView(tag) 50 | } 51 | } 52 | } 53 | .font(.footnote) 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /core/Sources/BookmarksCore/Views/TrailingDivider.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Jason Morley 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | import SwiftUI 22 | 23 | struct TrailingDivider: ViewModifier { 24 | 25 | func body(content: Content) -> some View { 26 | content 27 | Divider() 28 | } 29 | 30 | } 31 | 32 | extension View { 33 | 34 | public func trailingDivider() -> some View { 35 | modifier(TrailingDivider()) 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /core/Tests/BookmarksCoreTests/QueryDescriptionTests.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Jason Morley 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | import Foundation 22 | 23 | import XCTest 24 | @testable import BookmarksCore 25 | 26 | class QueryDescriptionTests: XCTestCase { 27 | 28 | func testTagQueryDescriptionSection() { 29 | let query = Tag("cheese") 30 | XCTAssertEqual(query.section, BookmarksSection.tag("cheese")) 31 | XCTAssertNotEqual(query.section, BookmarksSection.tag("fromage")) 32 | } 33 | 34 | func testAnyQueryEquality() { 35 | XCTAssertEqual(Tag("cheese").eraseToAnyQuery(), Tag("cheese").eraseToAnyQuery()) 36 | XCTAssertNotEqual(Tag("fromage").eraseToAnyQuery(), Tag("cheese").eraseToAnyQuery()) 37 | XCTAssertNotEqual(Today().eraseToAnyQuery(), Tag("cheese").eraseToAnyQuery()) 38 | } 39 | 40 | func testFilterParser() { 41 | XCTAssertEqual(AnyQuery.parse(filter: "tag:cheese"), Tag("cheese").eraseToAnyQuery()) 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /docs/.tool-versions: -------------------------------------------------------------------------------- 1 | ruby 3.1.2 -------------------------------------------------------------------------------- /docs/404.html: -------------------------------------------------------------------------------- 1 | --- 2 | permalink: /404.html 3 | layout: default 4 | --- 5 | 6 | 19 | 20 |
21 |

404

22 | 23 |

Page Not Found

24 |

The requested page could not be found.

25 |
26 | -------------------------------------------------------------------------------- /docs/CNAME: -------------------------------------------------------------------------------- 1 | bookmarks.jbmorley.co.uk -------------------------------------------------------------------------------- /docs/Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | # Hello! This is where you manage which Jekyll version is used to run. 3 | # When you want to use a different version, change it below, save the 4 | # file and run `bundle install`. Run Jekyll with `bundle exec`, like so: 5 | # 6 | # bundle exec jekyll serve 7 | # 8 | # This will help ensure the proper Jekyll version is running. 9 | # Happy Jekylling! 10 | gem "jekyll", "~> 4.2.0" 11 | # This is the default theme for new Jekyll sites. You may change this to anything you like. 12 | gem "minima", "~> 2.5" 13 | # If you want to use GitHub Pages, remove the "gem "jekyll"" above and 14 | # uncomment the line below. To upgrade, run `bundle update github-pages`. 15 | # gem "github-pages", group: :jekyll_plugins 16 | # If you have any plugins, put them here! 17 | group :jekyll_plugins do 18 | gem "jekyll-feed", "~> 0.12" 19 | end 20 | 21 | # Windows and JRuby does not include zoneinfo files, so bundle the tzinfo-data gem 22 | # and associated library. 23 | platforms :mingw, :x64_mingw, :mswin, :jruby do 24 | gem "tzinfo", "~> 1.2" 25 | gem "tzinfo-data" 26 | end 27 | 28 | # Performance-booster for watching directories on Windows 29 | gem "wdm", "~> 0.1.1", :platforms => [:mingw, :x64_mingw, :mswin] 30 | 31 | 32 | gem "webrick", "~> 1.8.2" 33 | gem "rexml", ">= 3.3.3" 34 | -------------------------------------------------------------------------------- /docs/_includes/footer.html: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /docs/_includes/navigation.html: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /docs/_layouts/default.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | {{ site.title }}{% if page.title %} - {{ page.title }}{% endif %} 7 | {% if page.description %}{% endif %} 8 | {% if site.author %}{% endif %} 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | {% include navigation.html %} 17 |
18 | {{ content }} 19 |
20 | {% include footer.html %} 21 | 22 | 23 | -------------------------------------------------------------------------------- /docs/images/icon_128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inseven/bookmarks/c684ceda7c4b865644df85ea6b0e0b9f20e5de10/docs/images/icon_128x128.png -------------------------------------------------------------------------------- /docs/images/icon_128x128@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inseven/bookmarks/c684ceda7c4b865644df85ea6b0e0b9f20e5de10/docs/images/icon_128x128@2x.png -------------------------------------------------------------------------------- /docs/index.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | title: About 3 | --- 4 | 5 |

6 | 10 |

11 | 12 | # Bookmarks 13 | 14 |

Pinboard client for Mac, iPhone and iPad

15 | -------------------------------------------------------------------------------- /docs/privacy-policy/index.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | title: Privacy Policy 3 | --- 4 | 5 | # Privacy Policy 6 | 7 | Bookmarks does not collect or store any personal data unless you have opted into crash reporting (details provided below). 8 | 9 | Should the policies outlined in this document change, we will make all reasonable efforts to inform you and provide mechanisms to opt-out. 10 | 11 | ## Crash Reporting 12 | 13 | If you have opted into crash reporting with Apple, we will occasionally receive crash logs from Apple which, ideally do not, but may contain personally identifiable information. Crash logs are stored privately and are kept confidential, and we will make all reasonable efforts to delete any found to contain personally identifiable information. 14 | 15 | ## Pinboard 16 | 17 | As a client for the Pinboard bookmarking service (https://pinboard.in), Bookmarks synchronizes data with Pinboard. Data stored in Pinboard is subject to their Privacy Policy (https://pinboard.in/privacy/). 18 | 19 | Bookmarks is not affiliated with Pinboard or Nine Fives Software and has no control over their Privacy Policy, or access to any information collected or stored as part of their service provision. 20 | 21 | ## Third-Party Websites 22 | 23 | Data processing necessary to select website thumbnails, index content for search, and enable other functionality, is performed entirely device-local within Bookmarks on iOS and macOS. Although Bookmarks does not utilize first- or third-party services when fetching this content, it is fetched from the URLs stored in your Pinboard account. Some of the authors of these websites may themselves employ tracking and analytics. Please refer to the privacy policies of these individual sites for more information. 24 | 25 | ## iCloud 26 | 27 | If you have enabled Apple iCloud services on the devices on which you run Bookmarks, application preferences and state may be stored in iCloud to facilitate a consistent experience across your devices. Data stored by Apple is subject to their Privacy Policy (https://www.apple.com/legal/privacy/). 28 | -------------------------------------------------------------------------------- /graphics/Bookmarks.symbolic: -------------------------------------------------------------------------------- 1 | {"systemImage":"bookmark","topColor":{"red":0.37984204290000001,"alpha":1,"blue":0.37984395030000001,"green":0.37984612579999999},"iconScale":0.82051805616258722,"id":"684FE5C5-E454-4790-9624-919254BF5FE2","symbolColor":{"red":1,"alpha":1,"blue":1,"green":1},"shadowOpacity":0.30650779884178336,"shadowHeight":0.29999999999999999,"bottomColor":{"red":0.12984204290000001,"alpha":1,"blue":0.12984395030000001,"green":0.12984612579999999}} -------------------------------------------------------------------------------- /graphics/Export/iOS/icon_1024x1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inseven/bookmarks/c684ceda7c4b865644df85ea6b0e0b9f20e5de10/graphics/Export/iOS/icon_1024x1024.png -------------------------------------------------------------------------------- /graphics/Export/iOS/icon_20x20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inseven/bookmarks/c684ceda7c4b865644df85ea6b0e0b9f20e5de10/graphics/Export/iOS/icon_20x20.png -------------------------------------------------------------------------------- /graphics/Export/iOS/icon_20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inseven/bookmarks/c684ceda7c4b865644df85ea6b0e0b9f20e5de10/graphics/Export/iOS/icon_20x20@2x.png -------------------------------------------------------------------------------- /graphics/Export/iOS/icon_20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inseven/bookmarks/c684ceda7c4b865644df85ea6b0e0b9f20e5de10/graphics/Export/iOS/icon_20x20@3x.png -------------------------------------------------------------------------------- /graphics/Export/iOS/icon_29x29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inseven/bookmarks/c684ceda7c4b865644df85ea6b0e0b9f20e5de10/graphics/Export/iOS/icon_29x29.png -------------------------------------------------------------------------------- /graphics/Export/iOS/icon_29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inseven/bookmarks/c684ceda7c4b865644df85ea6b0e0b9f20e5de10/graphics/Export/iOS/icon_29x29@2x.png -------------------------------------------------------------------------------- /graphics/Export/iOS/icon_29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inseven/bookmarks/c684ceda7c4b865644df85ea6b0e0b9f20e5de10/graphics/Export/iOS/icon_29x29@3x.png -------------------------------------------------------------------------------- /graphics/Export/iOS/icon_40x40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inseven/bookmarks/c684ceda7c4b865644df85ea6b0e0b9f20e5de10/graphics/Export/iOS/icon_40x40.png -------------------------------------------------------------------------------- /graphics/Export/iOS/icon_40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inseven/bookmarks/c684ceda7c4b865644df85ea6b0e0b9f20e5de10/graphics/Export/iOS/icon_40x40@2x.png -------------------------------------------------------------------------------- /graphics/Export/iOS/icon_40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inseven/bookmarks/c684ceda7c4b865644df85ea6b0e0b9f20e5de10/graphics/Export/iOS/icon_40x40@3x.png -------------------------------------------------------------------------------- /graphics/Export/iOS/icon_60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inseven/bookmarks/c684ceda7c4b865644df85ea6b0e0b9f20e5de10/graphics/Export/iOS/icon_60x60@2x.png -------------------------------------------------------------------------------- /graphics/Export/iOS/icon_60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inseven/bookmarks/c684ceda7c4b865644df85ea6b0e0b9f20e5de10/graphics/Export/iOS/icon_60x60@3x.png -------------------------------------------------------------------------------- /graphics/Export/iOS/icon_76x76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inseven/bookmarks/c684ceda7c4b865644df85ea6b0e0b9f20e5de10/graphics/Export/iOS/icon_76x76.png -------------------------------------------------------------------------------- /graphics/Export/iOS/icon_76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inseven/bookmarks/c684ceda7c4b865644df85ea6b0e0b9f20e5de10/graphics/Export/iOS/icon_76x76@2x.png -------------------------------------------------------------------------------- /graphics/Export/iOS/icon_83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inseven/bookmarks/c684ceda7c4b865644df85ea6b0e0b9f20e5de10/graphics/Export/iOS/icon_83.5x83.5@2x.png -------------------------------------------------------------------------------- /graphics/Export/icon_1024x1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inseven/bookmarks/c684ceda7c4b865644df85ea6b0e0b9f20e5de10/graphics/Export/icon_1024x1024.png -------------------------------------------------------------------------------- /graphics/Export/macOS.iconset/icon_128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inseven/bookmarks/c684ceda7c4b865644df85ea6b0e0b9f20e5de10/graphics/Export/macOS.iconset/icon_128x128.png -------------------------------------------------------------------------------- /graphics/Export/macOS.iconset/icon_128x128@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inseven/bookmarks/c684ceda7c4b865644df85ea6b0e0b9f20e5de10/graphics/Export/macOS.iconset/icon_128x128@2x.png -------------------------------------------------------------------------------- /graphics/Export/macOS.iconset/icon_16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inseven/bookmarks/c684ceda7c4b865644df85ea6b0e0b9f20e5de10/graphics/Export/macOS.iconset/icon_16x16.png -------------------------------------------------------------------------------- /graphics/Export/macOS.iconset/icon_16x16@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inseven/bookmarks/c684ceda7c4b865644df85ea6b0e0b9f20e5de10/graphics/Export/macOS.iconset/icon_16x16@2x.png -------------------------------------------------------------------------------- /graphics/Export/macOS.iconset/icon_256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inseven/bookmarks/c684ceda7c4b865644df85ea6b0e0b9f20e5de10/graphics/Export/macOS.iconset/icon_256x256.png -------------------------------------------------------------------------------- /graphics/Export/macOS.iconset/icon_256x256@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inseven/bookmarks/c684ceda7c4b865644df85ea6b0e0b9f20e5de10/graphics/Export/macOS.iconset/icon_256x256@2x.png -------------------------------------------------------------------------------- /graphics/Export/macOS.iconset/icon_32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inseven/bookmarks/c684ceda7c4b865644df85ea6b0e0b9f20e5de10/graphics/Export/macOS.iconset/icon_32x32.png -------------------------------------------------------------------------------- /graphics/Export/macOS.iconset/icon_32x32@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inseven/bookmarks/c684ceda7c4b865644df85ea6b0e0b9f20e5de10/graphics/Export/macOS.iconset/icon_32x32@2x.png -------------------------------------------------------------------------------- /graphics/Export/macOS.iconset/icon_512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inseven/bookmarks/c684ceda7c4b865644df85ea6b0e0b9f20e5de10/graphics/Export/macOS.iconset/icon_512x512.png -------------------------------------------------------------------------------- /graphics/Export/macOS.iconset/icon_512x512@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inseven/bookmarks/c684ceda7c4b865644df85ea6b0e0b9f20e5de10/graphics/Export/macOS.iconset/icon_512x512@2x.png -------------------------------------------------------------------------------- /graphics/iOS icon.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inseven/bookmarks/c684ceda7c4b865644df85ea6b0e0b9f20e5de10/graphics/iOS icon.ai -------------------------------------------------------------------------------- /graphics/macOS icon.sketch: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inseven/bookmarks/c684ceda7c4b865644df85ea6b0e0b9f20e5de10/graphics/macOS icon.sketch -------------------------------------------------------------------------------- /ios/Bookmarks Share Extension/Base.lproj/MainInterface.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /ios/Bookmarks Share Extension/Bookmarks Share Extension.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.application-groups 6 | 7 | group.uk.co.jbmorley.bookmarks 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ios/Bookmarks Share Extension/Bookmarks_Share_Extension.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | com.apple.security.files.user-selected.read-only 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ios/Bookmarks Share Extension/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSAppTransportSecurity 6 | 7 | NSAllowsArbitraryLoads 8 | 9 | 10 | NSExtension 11 | 12 | NSExtensionAttributes 13 | 14 | IntentsSupported 15 | 16 | NSExtensionActivationRule 17 | SUBQUERY ( 18 | extensionItems, 19 | $extensionItem, 20 | SUBQUERY ( 21 | $extensionItem.attachments, 22 | $attachment, 23 | ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "public.url" 24 | ).@count == $extensionItem.attachments.@count 25 | ).@count == 1 26 | 27 | 28 | NSExtensionMainStoryboard 29 | MainInterface 30 | NSExtensionPointIdentifier 31 | com.apple.share-services 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /ios/Bookmarks Share Extension/ShareViewController.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Jason Morley 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | import SwiftUI 22 | import UIKit 23 | 24 | class ShareViewController: UIHostingController, ShareExtensionDataSource { 25 | 26 | let extensionModel: ShareExtensionModel 27 | 28 | required init?(coder aDecoder: NSCoder) { 29 | let extensionModel = ShareExtensionModel() 30 | self.extensionModel = extensionModel 31 | super.init(rootView: RootView(extensionModel: extensionModel)) 32 | extensionModel.dataSource = self 33 | } 34 | 35 | override func viewDidAppear(_ animated: Bool) { 36 | super.viewDidAppear(animated) 37 | extensionModel.load() 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /ios/Bookmarks Share Extension/Views/RootView.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Jason Morley 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | import SwiftUI 22 | 23 | struct RootView: View { 24 | 25 | @ObservedObject var extensionModel: ShareExtensionModel 26 | 27 | var body: some View { 28 | NavigationStack { 29 | ContentView() 30 | .environmentObject(extensionModel) 31 | } 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /ios/Bookmarks Share Extension/icon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inseven/bookmarks/c684ceda7c4b865644df85ea6b0e0b9f20e5de10/ios/Bookmarks Share Extension/icon.icns -------------------------------------------------------------------------------- /ios/Bookmarks/Assets.xcassets/AppIcon.appiconset/icon_1024x1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inseven/bookmarks/c684ceda7c4b865644df85ea6b0e0b9f20e5de10/ios/Bookmarks/Assets.xcassets/AppIcon.appiconset/icon_1024x1024.png -------------------------------------------------------------------------------- /ios/Bookmarks/Assets.xcassets/AppIcon.appiconset/icon_20x20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inseven/bookmarks/c684ceda7c4b865644df85ea6b0e0b9f20e5de10/ios/Bookmarks/Assets.xcassets/AppIcon.appiconset/icon_20x20.png -------------------------------------------------------------------------------- /ios/Bookmarks/Assets.xcassets/AppIcon.appiconset/icon_20x20@2x 1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inseven/bookmarks/c684ceda7c4b865644df85ea6b0e0b9f20e5de10/ios/Bookmarks/Assets.xcassets/AppIcon.appiconset/icon_20x20@2x 1.png -------------------------------------------------------------------------------- /ios/Bookmarks/Assets.xcassets/AppIcon.appiconset/icon_20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inseven/bookmarks/c684ceda7c4b865644df85ea6b0e0b9f20e5de10/ios/Bookmarks/Assets.xcassets/AppIcon.appiconset/icon_20x20@2x.png -------------------------------------------------------------------------------- /ios/Bookmarks/Assets.xcassets/AppIcon.appiconset/icon_20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inseven/bookmarks/c684ceda7c4b865644df85ea6b0e0b9f20e5de10/ios/Bookmarks/Assets.xcassets/AppIcon.appiconset/icon_20x20@3x.png -------------------------------------------------------------------------------- /ios/Bookmarks/Assets.xcassets/AppIcon.appiconset/icon_29x29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inseven/bookmarks/c684ceda7c4b865644df85ea6b0e0b9f20e5de10/ios/Bookmarks/Assets.xcassets/AppIcon.appiconset/icon_29x29.png -------------------------------------------------------------------------------- /ios/Bookmarks/Assets.xcassets/AppIcon.appiconset/icon_29x29@2x 1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inseven/bookmarks/c684ceda7c4b865644df85ea6b0e0b9f20e5de10/ios/Bookmarks/Assets.xcassets/AppIcon.appiconset/icon_29x29@2x 1.png -------------------------------------------------------------------------------- /ios/Bookmarks/Assets.xcassets/AppIcon.appiconset/icon_29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inseven/bookmarks/c684ceda7c4b865644df85ea6b0e0b9f20e5de10/ios/Bookmarks/Assets.xcassets/AppIcon.appiconset/icon_29x29@2x.png -------------------------------------------------------------------------------- /ios/Bookmarks/Assets.xcassets/AppIcon.appiconset/icon_29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inseven/bookmarks/c684ceda7c4b865644df85ea6b0e0b9f20e5de10/ios/Bookmarks/Assets.xcassets/AppIcon.appiconset/icon_29x29@3x.png -------------------------------------------------------------------------------- /ios/Bookmarks/Assets.xcassets/AppIcon.appiconset/icon_40x40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inseven/bookmarks/c684ceda7c4b865644df85ea6b0e0b9f20e5de10/ios/Bookmarks/Assets.xcassets/AppIcon.appiconset/icon_40x40.png -------------------------------------------------------------------------------- /ios/Bookmarks/Assets.xcassets/AppIcon.appiconset/icon_40x40@2x 1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inseven/bookmarks/c684ceda7c4b865644df85ea6b0e0b9f20e5de10/ios/Bookmarks/Assets.xcassets/AppIcon.appiconset/icon_40x40@2x 1.png -------------------------------------------------------------------------------- /ios/Bookmarks/Assets.xcassets/AppIcon.appiconset/icon_40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inseven/bookmarks/c684ceda7c4b865644df85ea6b0e0b9f20e5de10/ios/Bookmarks/Assets.xcassets/AppIcon.appiconset/icon_40x40@2x.png -------------------------------------------------------------------------------- /ios/Bookmarks/Assets.xcassets/AppIcon.appiconset/icon_40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inseven/bookmarks/c684ceda7c4b865644df85ea6b0e0b9f20e5de10/ios/Bookmarks/Assets.xcassets/AppIcon.appiconset/icon_40x40@3x.png -------------------------------------------------------------------------------- /ios/Bookmarks/Assets.xcassets/AppIcon.appiconset/icon_60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inseven/bookmarks/c684ceda7c4b865644df85ea6b0e0b9f20e5de10/ios/Bookmarks/Assets.xcassets/AppIcon.appiconset/icon_60x60@2x.png -------------------------------------------------------------------------------- /ios/Bookmarks/Assets.xcassets/AppIcon.appiconset/icon_60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inseven/bookmarks/c684ceda7c4b865644df85ea6b0e0b9f20e5de10/ios/Bookmarks/Assets.xcassets/AppIcon.appiconset/icon_60x60@3x.png -------------------------------------------------------------------------------- /ios/Bookmarks/Assets.xcassets/AppIcon.appiconset/icon_76x76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inseven/bookmarks/c684ceda7c4b865644df85ea6b0e0b9f20e5de10/ios/Bookmarks/Assets.xcassets/AppIcon.appiconset/icon_76x76.png -------------------------------------------------------------------------------- /ios/Bookmarks/Assets.xcassets/AppIcon.appiconset/icon_76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inseven/bookmarks/c684ceda7c4b865644df85ea6b0e0b9f20e5de10/ios/Bookmarks/Assets.xcassets/AppIcon.appiconset/icon_76x76@2x.png -------------------------------------------------------------------------------- /ios/Bookmarks/Assets.xcassets/AppIcon.appiconset/icon_83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inseven/bookmarks/c684ceda7c4b865644df85ea6b0e0b9f20e5de10/ios/Bookmarks/Assets.xcassets/AppIcon.appiconset/icon_83.5x83.5@2x.png -------------------------------------------------------------------------------- /ios/Bookmarks/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /ios/Bookmarks/Assets.xcassets/Icon.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "icon_1024x1024.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /ios/Bookmarks/Assets.xcassets/Icon.imageset/icon_1024x1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inseven/bookmarks/c684ceda7c4b865644df85ea6b0e0b9f20e5de10/ios/Bookmarks/Assets.xcassets/Icon.imageset/icon_1024x1024.png -------------------------------------------------------------------------------- /ios/Bookmarks/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /ios/Bookmarks/Bookmarks-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Jason Morley 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | -------------------------------------------------------------------------------- /ios/Bookmarks/Bookmarks.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | com.apple.security.application-groups 8 | 9 | group.uk.co.jbmorley.bookmarks 10 | 11 | com.apple.security.network.client 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /ios/Bookmarks/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | $(MARKETING_VERSION) 19 | CFBundleURLTypes 20 | 21 | 22 | CFBundleTypeRole 23 | Editor 24 | CFBundleURLName 25 | uk.co.jbmorley.bookmarks.types.action 26 | CFBundleURLSchemes 27 | 28 | bookmarks-action 29 | 30 | 31 | 32 | CFBundleVersion 33 | $(CURRENT_PROJECT_VERSION) 34 | ITSAppUsesNonExemptEncryption 35 | 36 | LSRequiresIPhoneOS 37 | 38 | NSAppTransportSecurity 39 | 40 | NSAllowsArbitraryLoads 41 | 42 | 43 | UILaunchStoryboardName 44 | LaunchScreen 45 | UIRequiredDeviceCapabilities 46 | 47 | armv7 48 | 49 | UISupportedInterfaceOrientations 50 | 51 | UIInterfaceOrientationPortrait 52 | UIInterfaceOrientationLandscapeLeft 53 | UIInterfaceOrientationLandscapeRight 54 | 55 | UISupportedInterfaceOrientations~ipad 56 | 57 | UIInterfaceOrientationPortrait 58 | UIInterfaceOrientationPortraitUpsideDown 59 | UIInterfaceOrientationLandscapeLeft 60 | UIInterfaceOrientationLandscapeRight 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /ios/BookmarksTests/BookmarksTests.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Jason Morley 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | import XCTest 22 | @testable import Bookmarks 23 | 24 | class BookmarksTests: XCTestCase { 25 | 26 | } 27 | -------------------------------------------------------------------------------- /ios/BookmarksTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /ios/BookmarksUITests/BookmarksUITests.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Jason Morley 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | import XCTest 22 | 23 | class BookmarksUITests: XCTestCase { 24 | 25 | } 26 | -------------------------------------------------------------------------------- /ios/BookmarksUITests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /ios/Common.xcconfig: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Jason Morley 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | BUILD_NUMBER = 1000 22 | -------------------------------------------------------------------------------- /ios/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Jason Morley 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | #include "Common.xcconfig" 22 | -------------------------------------------------------------------------------- /ios/ExportOptions.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | destination 6 | export 7 | manageAppVersionAndBuildNumber 8 | 9 | method 10 | app-store-connect 11 | provisioningProfiles 12 | 13 | uk.co.jbmorley.bookmarks.apps.appstore 14 | Bookmarks App Store Profile 15 | uk.co.jbmorley.bookmarks.apps.appstore.share-extension 16 | Bookmarks Share Extension App Store Profile 17 | 18 | signingCertificate 19 | Apple Distribution 20 | signingStyle 21 | manual 22 | stripSwiftSymbols 23 | 24 | teamID 25 | QS82QFHKWB 26 | uploadSymbols 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /ios/Release.xcconfig: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Jason Morley 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | #include "Common.xcconfig" 22 | -------------------------------------------------------------------------------- /macos/Bookmarks/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 | -------------------------------------------------------------------------------- /macos/Bookmarks/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "icon_16x16.png", 5 | "idiom" : "mac", 6 | "scale" : "1x", 7 | "size" : "16x16" 8 | }, 9 | { 10 | "filename" : "icon_16x16@2x.png", 11 | "idiom" : "mac", 12 | "scale" : "2x", 13 | "size" : "16x16" 14 | }, 15 | { 16 | "filename" : "icon_32x32.png", 17 | "idiom" : "mac", 18 | "scale" : "1x", 19 | "size" : "32x32" 20 | }, 21 | { 22 | "filename" : "icon_32x32@2x.png", 23 | "idiom" : "mac", 24 | "scale" : "2x", 25 | "size" : "32x32" 26 | }, 27 | { 28 | "filename" : "icon_128x128.png", 29 | "idiom" : "mac", 30 | "scale" : "1x", 31 | "size" : "128x128" 32 | }, 33 | { 34 | "filename" : "icon_128x128@2x.png", 35 | "idiom" : "mac", 36 | "scale" : "2x", 37 | "size" : "128x128" 38 | }, 39 | { 40 | "filename" : "icon_256x256.png", 41 | "idiom" : "mac", 42 | "scale" : "1x", 43 | "size" : "256x256" 44 | }, 45 | { 46 | "filename" : "icon_256x256@2x.png", 47 | "idiom" : "mac", 48 | "scale" : "2x", 49 | "size" : "256x256" 50 | }, 51 | { 52 | "filename" : "icon_512x512.png", 53 | "idiom" : "mac", 54 | "scale" : "1x", 55 | "size" : "512x512" 56 | }, 57 | { 58 | "filename" : "icon_512x512@2x.png", 59 | "idiom" : "mac", 60 | "scale" : "2x", 61 | "size" : "512x512" 62 | } 63 | ], 64 | "info" : { 65 | "author" : "xcode", 66 | "version" : 1 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /macos/Bookmarks/Assets.xcassets/AppIcon.appiconset/icon_128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inseven/bookmarks/c684ceda7c4b865644df85ea6b0e0b9f20e5de10/macos/Bookmarks/Assets.xcassets/AppIcon.appiconset/icon_128x128.png -------------------------------------------------------------------------------- /macos/Bookmarks/Assets.xcassets/AppIcon.appiconset/icon_128x128@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inseven/bookmarks/c684ceda7c4b865644df85ea6b0e0b9f20e5de10/macos/Bookmarks/Assets.xcassets/AppIcon.appiconset/icon_128x128@2x.png -------------------------------------------------------------------------------- /macos/Bookmarks/Assets.xcassets/AppIcon.appiconset/icon_16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inseven/bookmarks/c684ceda7c4b865644df85ea6b0e0b9f20e5de10/macos/Bookmarks/Assets.xcassets/AppIcon.appiconset/icon_16x16.png -------------------------------------------------------------------------------- /macos/Bookmarks/Assets.xcassets/AppIcon.appiconset/icon_16x16@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inseven/bookmarks/c684ceda7c4b865644df85ea6b0e0b9f20e5de10/macos/Bookmarks/Assets.xcassets/AppIcon.appiconset/icon_16x16@2x.png -------------------------------------------------------------------------------- /macos/Bookmarks/Assets.xcassets/AppIcon.appiconset/icon_256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inseven/bookmarks/c684ceda7c4b865644df85ea6b0e0b9f20e5de10/macos/Bookmarks/Assets.xcassets/AppIcon.appiconset/icon_256x256.png -------------------------------------------------------------------------------- /macos/Bookmarks/Assets.xcassets/AppIcon.appiconset/icon_256x256@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inseven/bookmarks/c684ceda7c4b865644df85ea6b0e0b9f20e5de10/macos/Bookmarks/Assets.xcassets/AppIcon.appiconset/icon_256x256@2x.png -------------------------------------------------------------------------------- /macos/Bookmarks/Assets.xcassets/AppIcon.appiconset/icon_32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inseven/bookmarks/c684ceda7c4b865644df85ea6b0e0b9f20e5de10/macos/Bookmarks/Assets.xcassets/AppIcon.appiconset/icon_32x32.png -------------------------------------------------------------------------------- /macos/Bookmarks/Assets.xcassets/AppIcon.appiconset/icon_32x32@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inseven/bookmarks/c684ceda7c4b865644df85ea6b0e0b9f20e5de10/macos/Bookmarks/Assets.xcassets/AppIcon.appiconset/icon_32x32@2x.png -------------------------------------------------------------------------------- /macos/Bookmarks/Assets.xcassets/AppIcon.appiconset/icon_512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inseven/bookmarks/c684ceda7c4b865644df85ea6b0e0b9f20e5de10/macos/Bookmarks/Assets.xcassets/AppIcon.appiconset/icon_512x512.png -------------------------------------------------------------------------------- /macos/Bookmarks/Assets.xcassets/AppIcon.appiconset/icon_512x512@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inseven/bookmarks/c684ceda7c4b865644df85ea6b0e0b9f20e5de10/macos/Bookmarks/Assets.xcassets/AppIcon.appiconset/icon_512x512@2x.png -------------------------------------------------------------------------------- /macos/Bookmarks/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /macos/Bookmarks/Assets.xcassets/Icon.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "icon_512x512.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "filename" : "icon_512x512@2x.png", 10 | "idiom" : "universal", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /macos/Bookmarks/Assets.xcassets/Icon.imageset/icon_512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inseven/bookmarks/c684ceda7c4b865644df85ea6b0e0b9f20e5de10/macos/Bookmarks/Assets.xcassets/Icon.imageset/icon_512x512.png -------------------------------------------------------------------------------- /macos/Bookmarks/Assets.xcassets/Icon.imageset/icon_512x512@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inseven/bookmarks/c684ceda7c4b865644df85ea6b0e0b9f20e5de10/macos/Bookmarks/Assets.xcassets/Icon.imageset/icon_512x512@2x.png -------------------------------------------------------------------------------- /macos/Bookmarks/Assets.xcassets/PinboardLogo.imageset/Artboard 1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inseven/bookmarks/c684ceda7c4b865644df85ea6b0e0b9f20e5de10/macos/Bookmarks/Assets.xcassets/PinboardLogo.imageset/Artboard 1.png -------------------------------------------------------------------------------- /macos/Bookmarks/Assets.xcassets/PinboardLogo.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "Artboard 1.png", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /macos/Bookmarks/Bookmarks.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | com.apple.security.application-groups 8 | 9 | group.uk.co.jbmorley.bookmarks 10 | 11 | com.apple.security.files.user-selected.read-only 12 | 13 | com.apple.security.network.client 14 | 15 | com.apple.security.network.server 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /macos/Bookmarks/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | $(MARKETING_VERSION) 19 | CFBundleURLTypes 20 | 21 | 22 | CFBundleTypeRole 23 | Editor 24 | CFBundleURLName 25 | uk.co.jbmorley.bookmarks.types.action 26 | CFBundleURLSchemes 27 | 28 | bookmarks-action 29 | 30 | 31 | 32 | CFBundleVersion 33 | $(CURRENT_PROJECT_VERSION) 34 | ITSAppUsesNonExemptEncryption 35 | 36 | LSApplicationCategoryType 37 | public.app-category.utilities 38 | LSMinimumSystemVersion 39 | $(MACOSX_DEPLOYMENT_TARGET) 40 | NSAppTransportSecurity 41 | 42 | NSAllowsArbitraryLoads 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /macos/Bookmarks/Preview Content/Preview Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /macos/Bookmarks/Views/SettingsView.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Jason Morley 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | import SwiftUI 22 | 23 | import BookmarksCore 24 | 25 | struct SettingsView: View { 26 | 27 | private enum Tabs: Hashable { 28 | case general 29 | case debug 30 | } 31 | 32 | @EnvironmentObject var applicationModel: ApplicationModel 33 | 34 | var body: some View { 35 | TabView { 36 | Form { 37 | SidebarSettingsSection(settings: applicationModel.settings) 38 | } 39 | .tabItem { 40 | Label("General", systemImage: "gear") 41 | } 42 | .tag(Tabs.general) 43 | AdvancedSettingsView() 44 | .tabItem { 45 | Label("Advanced", systemImage: "magnifyingglass") 46 | } 47 | .tag(Tabs.debug) 48 | } 49 | .padding() 50 | .frame(minWidth: 320, maxWidth: .infinity) 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /macos/BookmarksTests/BookmarksTests.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Jason Morley 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | import XCTest 22 | @testable import Bookmarks 23 | 24 | class BookmarksTests: XCTestCase { 25 | 26 | } 27 | -------------------------------------------------------------------------------- /macos/BookmarksTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /macos/BookmarksUITests/BookmarksUITests.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Jason Morley 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | import XCTest 22 | 23 | class BookmarksUITests: XCTestCase { 24 | 25 | } 26 | -------------------------------------------------------------------------------- /macos/BookmarksUITests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /macos/Common.xcconfig: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Jason Morley 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | BUILD_NUMBER = 1000 22 | -------------------------------------------------------------------------------- /macos/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Jason Morley 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | #include "Common.xcconfig" 22 | -------------------------------------------------------------------------------- /macos/ExportOptions.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | destination 6 | export 7 | installerSigningCertificate 8 | 3rd Party Mac Developer Installer 9 | manageAppVersionAndBuildNumber 10 | 11 | method 12 | app-store-connect 13 | provisioningProfiles 14 | 15 | uk.co.jbmorley.bookmarks.apps.appstore 16 | Bookmarks Mac App Store Profile 17 | uk.co.jbmorley.bookmarks.apps.appstore.safari-extension 18 | Bookmarks Safari Extension Mac App Store Profile 19 | 20 | signingCertificate 21 | Apple Distribution 22 | signingStyle 23 | manual 24 | teamID 25 | QS82QFHKWB 26 | uploadSymbols 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /macos/Release.xcconfig: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Jason Morley 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | #include "Common.xcconfig" 22 | -------------------------------------------------------------------------------- /macos/SafariExtension/Base.lproj/SafariExtensionViewController.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /macos/SafariExtension/HostedContentView.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Jason Morley 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | import SwiftUI 22 | 23 | import BookmarksCore 24 | 25 | class HostedContentView: NSView { 26 | 27 | let extensionModel = SafariExtensionModel() 28 | 29 | required init?(coder aDecoder: NSCoder) { 30 | super.init(coder: aDecoder) 31 | 32 | let content = NSHostingView(rootView: ContentView() 33 | .environmentObject(extensionModel)) 34 | content.translatesAutoresizingMaskIntoConstraints = false 35 | 36 | self.addSubview(content) 37 | content.leadingAnchor.constraint(equalTo: self.leadingAnchor).isActive = true 38 | content.trailingAnchor.constraint(equalTo: self.trailingAnchor).isActive = true 39 | content.topAnchor.constraint(equalTo: self.topAnchor).isActive = true 40 | content.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /macos/SafariExtension/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSExtension 6 | 7 | NSExtensionPointIdentifier 8 | com.apple.Safari.extension 9 | NSExtensionPrincipalClass 10 | $(PRODUCT_MODULE_NAME).SafariExtensionHandler 11 | SFSafariContentScript 12 | 13 | 14 | Script 15 | script.js 16 | 17 | 18 | SFSafariToolbarItem 19 | 20 | Action 21 | Popover 22 | Identifier 23 | Button 24 | Image 25 | ToolbarItemIcon.pdf 26 | Label 27 | Bookmarks 28 | 29 | SFSafariWebsiteAccess 30 | 31 | Allowed Domains 32 | 33 | example.com 34 | 35 | Level 36 | All 37 | 38 | 39 | NSHumanReadableDescription 40 | This is Bookmarks Extension. You should tell us what your extension does here. 41 | 42 | 43 | -------------------------------------------------------------------------------- /macos/SafariExtension/Resources/ToolbarItemIcon.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inseven/bookmarks/c684ceda7c4b865644df85ea6b0e0b9f20e5de10/macos/SafariExtension/Resources/ToolbarItemIcon.pdf -------------------------------------------------------------------------------- /macos/SafariExtension/Resources/script.js: -------------------------------------------------------------------------------- 1 | document.addEventListener("DOMContentLoaded", function(event) { 2 | safari.extension.dispatchMessage("Hello World!"); 3 | }); 4 | -------------------------------------------------------------------------------- /macos/SafariExtension/SafariExtension.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | com.apple.security.application-groups 8 | 9 | group.uk.co.jbmorley.bookmarks 10 | 11 | com.apple.security.files.user-selected.read-only 12 | 13 | com.apple.security.network.client 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /macos/SafariExtension/SafariExtensionViewController.swift: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2025 Jason Morley 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | import SafariServices 22 | 23 | class SafariExtensionViewController: SFSafariExtensionViewController { 24 | 25 | static let shared: SafariExtensionViewController = { 26 | let shared = SafariExtensionViewController() 27 | shared.preferredContentSize = NSSize(width:320, height:240) 28 | return shared 29 | }() 30 | 31 | } 32 | -------------------------------------------------------------------------------- /profiles/Bookmarks_App_Store_Profile.mobileprovision: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inseven/bookmarks/c684ceda7c4b865644df85ea6b0e0b9f20e5de10/profiles/Bookmarks_App_Store_Profile.mobileprovision -------------------------------------------------------------------------------- /profiles/Bookmarks_Mac_App_Store_Profile.provisionprofile: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inseven/bookmarks/c684ceda7c4b865644df85ea6b0e0b9f20e5de10/profiles/Bookmarks_Mac_App_Store_Profile.provisionprofile -------------------------------------------------------------------------------- /profiles/Bookmarks_Safari_Extension_Mac_App_Store_Profile.provisionprofile: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inseven/bookmarks/c684ceda7c4b865644df85ea6b0e0b9f20e5de10/profiles/Bookmarks_Safari_Extension_Mac_App_Store_Profile.provisionprofile -------------------------------------------------------------------------------- /profiles/Bookmarks_Share_Extension_App_Store_Profile.mobileprovision: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inseven/bookmarks/c684ceda7c4b865644df85ea6b0e0b9f20e5de10/profiles/Bookmarks_Share_Extension_App_Store_Profile.mobileprovision -------------------------------------------------------------------------------- /screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inseven/bookmarks/c684ceda7c4b865644df85ea6b0e0b9f20e5de10/screenshot.png -------------------------------------------------------------------------------- /scripts/environment.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright (c) 2020-2025 Jason Morley 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | 23 | SCRIPTS_DIRECTORY="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" 24 | ROOT_DIRECTORY="${SCRIPTS_DIRECTORY}/.." 25 | 26 | export PYTHONUSERBASE="${ROOT_DIRECTORY}/.local/python" 27 | mkdir -p "$PYTHONUSERBASE" 28 | export PATH="${PYTHONUSERBASE}/bin":$PATH 29 | 30 | export PATH=$PATH:"${SCRIPTS_DIRECTORY}/changes" 31 | export PATH=$PATH:"${SCRIPTS_DIRECTORY}/build-tools" 32 | export PATH=$PATH:"${ROOT_DIRECTORY}/diligence/scripts" 33 | -------------------------------------------------------------------------------- /scripts/install-dependencies.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright (c) 2020-2025 Jason Morley 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | 23 | set -e 24 | set -o pipefail 25 | set -x 26 | set -u 27 | 28 | scripts_directory="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" 29 | root_directory="${scripts_directory}/.." 30 | changes_directory="${scripts_directory}/changes" 31 | build_tools_directory="${scripts_directory}/build-tools" 32 | 33 | environment_path="${scripts_directory}/environment.sh" 34 | 35 | source "$environment_path" 36 | 37 | # Install the Python dependencies 38 | PIPENV_PIPFILE="$changes_directory/Pipfile" pipenv install 39 | PIPENV_PIPFILE="$build_tools_directory/Pipfile" pipenv install 40 | 41 | cd "$root_directory" 42 | -------------------------------------------------------------------------------- /scripts/release-notes.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | title: Release Notes 3 | --- 4 | 5 | # Release Notes 6 | 7 | {% for release in releases | selectattr("is_initial_development", "false") -%} 8 | ## {{ release.version }}{% if not release.is_released %} (Unreleased){% endif %} 9 | {% for section in release.sections %} 10 | **{{ section.title }}** 11 | 12 | {% for change in section.changes | reverse -%} 13 | - {{ change.description }}{% if change.scope %}{{ change.scope }}{% endif %} 14 | {% endfor %}{% endfor %} 15 | {% endfor %} 16 | -------------------------------------------------------------------------------- /scripts/update-release-notes.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright (c) 2021-2023 Jason Morley, Tom Sutcliffe 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | 23 | set -e 24 | set -o pipefail 25 | set -x 26 | set -u 27 | 28 | SCRIPTS_DIRECTORY="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" 29 | 30 | ROOT_DIRECTORY="${SCRIPTS_DIRECTORY}/.." 31 | RELEASE_NOTES_TEMPLATE_PATH="${SCRIPTS_DIRECTORY}/release-notes.markdown" 32 | HISTORY_PATH="${SCRIPTS_DIRECTORY}/history.yaml" 33 | RELEASE_NOTES_DIRECTORY="${ROOT_DIRECTORY}/docs/release-notes" 34 | RELEASE_NOTES_PATH="${RELEASE_NOTES_DIRECTORY}/index.markdown" 35 | 36 | source "${SCRIPTS_DIRECTORY}/environment.sh" 37 | 38 | 39 | cd "$ROOT_DIRECTORY" 40 | 41 | mkdir -p "$RELEASE_NOTES_DIRECTORY" 42 | changes notes --all --released --history "$HISTORY_PATH" --template "$RELEASE_NOTES_TEMPLATE_PATH" > "$RELEASE_NOTES_PATH" 43 | --------------------------------------------------------------------------------