diff options
| author | Christian Cleberg <[email protected]> | 2026-07-17 08:36:05 -0500 |
|---|---|---|
| committer | Christian Cleberg <[email protected]> | 2026-07-17 10:12:36 -0500 |
| commit | b4b94d54cbed9334a28cdcd70d3a8a0fd06e04ef (patch) | |
| tree | 8fa4b408729da32ec2c547081ec2bba13b893fa2 /DomainDigShareExtension | |
| parent | 065e1e77ff00e8f9c8785393b5eba6c3e0bb2bb1 (diff) | |
| download | domain-dig-b4b94d54cbed9334a28cdcd70d3a8a0fd06e04ef.tar.gz domain-dig-b4b94d54cbed9334a28cdcd70d3a8a0fd06e04ef.tar.bz2 domain-dig-b4b94d54cbed9334a28cdcd70d3a8a0fd06e04ef.zip | |
Implement v4.6.0: sweep Live Activity, share extension, iPad split view, actionable notifications
- Sweep Live Activity: SweepActivityAttributes (Shared/), lock-screen + Dynamic
Island UI in the widget extension, driven by SweepActivityController wired into
the batch pipeline (begin/update/end); NSSupportsLiveActivities in Info.plist.
- Share extension (DomainDigShareExtension): accepts a web URL from the share
sheet, extracts the host, and hands it to the app via the App Group inbox
(DomainDigShareInbox); the app consumes it on activation and inspects it.
- iPad layout: RootTabView uses NavigationSplitView in the regular size class
and the tab bar in compact.
- Actionable notifications: per-domain threadIdentifier grouping, a Re-inspect
action, and tap routing into the domain detail via the intent router.
- Bump version to 4.6.0 (build 38) across app, widget, and share targets.
Diffstat (limited to 'DomainDigShareExtension')
| -rw-r--r-- | DomainDigShareExtension/DomainDigShareExtension.entitlements | 10 | ||||
| -rw-r--r-- | DomainDigShareExtension/Info.plist | 39 | ||||
| -rw-r--r-- | DomainDigShareExtension/ShareViewController.swift | 65 |
3 files changed, 114 insertions, 0 deletions
diff --git a/DomainDigShareExtension/DomainDigShareExtension.entitlements b/DomainDigShareExtension/DomainDigShareExtension.entitlements new file mode 100644 index 0000000..eaa20ba --- /dev/null +++ b/DomainDigShareExtension/DomainDigShareExtension.entitlements @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>com.apple.security.application-groups</key> + <array> + <string>group.net.cleberg.DomainDig</string> + </array> +</dict> +</plist> diff --git a/DomainDigShareExtension/Info.plist b/DomainDigShareExtension/Info.plist new file mode 100644 index 0000000..ac17ff0 --- /dev/null +++ b/DomainDigShareExtension/Info.plist @@ -0,0 +1,39 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>CFBundleDevelopmentRegion</key> + <string>$(DEVELOPMENT_LANGUAGE)</string> + <key>CFBundleDisplayName</key> + <string>Dig Domain</string> + <key>CFBundleExecutable</key> + <string>$(EXECUTABLE_NAME)</string> + <key>CFBundleIdentifier</key> + <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string> + <key>CFBundleInfoDictionaryVersion</key> + <string>6.0</string> + <key>CFBundleName</key> + <string>$(PRODUCT_NAME)</string> + <key>CFBundlePackageType</key> + <string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string> + <key>CFBundleShortVersionString</key> + <string>$(MARKETING_VERSION)</string> + <key>CFBundleVersion</key> + <string>$(CURRENT_PROJECT_VERSION)</string> + <key>NSExtension</key> + <dict> + <key>NSExtensionAttributes</key> + <dict> + <key>NSExtensionActivationRule</key> + <dict> + <key>NSExtensionActivationSupportsWebURLWithMaxCount</key> + <integer>1</integer> + </dict> + </dict> + <key>NSExtensionPointIdentifier</key> + <string>com.apple.share-services</string> + <key>NSExtensionPrincipalClass</key> + <string>$(PRODUCT_MODULE_NAME).ShareViewController</string> + </dict> +</dict> +</plist> diff --git a/DomainDigShareExtension/ShareViewController.swift b/DomainDigShareExtension/ShareViewController.swift new file mode 100644 index 0000000..411f9e7 --- /dev/null +++ b/DomainDigShareExtension/ShareViewController.swift @@ -0,0 +1,65 @@ +import UIKit +import UniformTypeIdentifiers + +/// Receives a web URL from the share sheet, extracts its host, and hands it to +/// the app through the App Group inbox. Shows a brief confirmation and closes; +/// the app picks up the domain the next time it becomes active. +final class ShareViewController: UIViewController { + private let label = UILabel() + + override func viewDidLoad() { + super.viewDidLoad() + view.backgroundColor = .systemBackground + + label.text = "Saving…" + label.font = .preferredFont(forTextStyle: .headline) + label.textAlignment = .center + label.numberOfLines = 0 + label.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(label) + NSLayoutConstraint.activate([ + label.centerXAnchor.constraint(equalTo: view.centerXAnchor), + label.centerYAnchor.constraint(equalTo: view.centerYAnchor), + label.leadingAnchor.constraint(greaterThanOrEqualTo: view.leadingAnchor, constant: 24), + label.trailingAnchor.constraint(lessThanOrEqualTo: view.trailingAnchor, constant: -24) + ]) + + extractSharedDomain { [weak self] domain in + DispatchQueue.main.async { + self?.finish(domain: domain) + } + } + } + + private func extractSharedDomain(completion: @escaping (String?) -> Void) { + let providers = (extensionContext?.inputItems ?? []) + .compactMap { $0 as? NSExtensionItem } + .flatMap { $0.attachments ?? [] } + + guard let provider = providers.first(where: { + $0.hasItemConformingToTypeIdentifier(UTType.url.identifier) + }) else { + completion(nil) + return + } + + provider.loadItem(forTypeIdentifier: UTType.url.identifier) { item, _ in + let url = item as? URL ?? (item as? Data).flatMap { URL(dataRepresentation: $0, relativeTo: nil) } + let host = url?.host?.trimmingCharacters(in: .whitespacesAndNewlines) + completion(host?.isEmpty == false ? host : nil) + } + } + + private func finish(domain: String?) { + if let domain { + DomainDigShareInbox.write(domain: domain) + label.text = "Saved \(domain) — open DomainDig to inspect it." + } else { + label.text = "No web address found." + } + + DispatchQueue.main.asyncAfter(deadline: .now() + 1.4) { [weak self] in + self?.extensionContext?.completeRequest(returningItems: nil) + } + } +} |
