Compare commits

..

No commits in common. "9b3cc61dcbcedd83d0c9debb1457b1adecac4048" and "5b70c713b2829a39332c7e33f01f55566e6f32fb" have entirely different histories.

14 changed files with 48 additions and 67 deletions

View File

@ -16,7 +16,7 @@ let package = Package(
],
dependencies: [
// Dependencies declare other packages that this package depends on.
.package(url: "https://github.com/karwa/swift-url.git", branch: "main"),
.package(url: "https://github.com/karwa/swift-url.git", from: "0.3.1"),
],
targets: [
// Targets are the basic building blocks of a package. A target can define a module or a test suite.

View File

@ -12,13 +12,13 @@ import WebURLFoundationExtras
public class Hashtag: Codable {
public let name: String
public let url: WebURL
public let url: URL
/// Only present when returned from the trending hashtags endpoint
public let history: [History]?
public init(name: String, url: URL) {
self.name = name
self.url = WebURL(url)!
self.url = url
self.history = nil
}
@ -26,14 +26,24 @@ public class Hashtag: Codable {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.name = try container.decode(String.self, forKey: .name)
// pixelfed (possibly others) don't fully escape special characters in the hashtag url
self.url = try container.decode(WebURL.self, forKey: .url)
do {
let webURL = try container.decode(WebURL.self, forKey: .url)
if let url = URL(webURL) {
self.url = url
} else {
let s = try? container.decode(String.self, forKey: .url)
throw DecodingError.dataCorruptedError(forKey: .url, in: container, debugDescription: "unable to convert WebURL \(s?.debugDescription ?? "nil") to URL")
}
} catch {
self.url = try container.decode(URL.self, forKey: .url)
}
self.history = try container.decodeIfPresent([History].self, forKey: .history)
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(name, forKey: .name)
try container.encode(url, forKey: .url)
try container.encode(url.absoluteString, forKey: .url)
try container.encodeIfPresent(history, forKey: .history)
}

View File

@ -8,9 +8,10 @@
import Foundation
import WebURL
import WebURLFoundationExtras
public class Mention: Codable {
public let url: WebURL
public let url: URL
public let username: String
public let acct: String
/// The instance-local ID of the user being mentioned.
@ -21,7 +22,17 @@ public class Mention: Codable {
self.username = try container.decode(String.self, forKey: .username)
self.acct = try container.decode(String.self, forKey: .acct)
self.id = try container.decode(String.self, forKey: .id)
self.url = try container.decode(WebURL.self, forKey: .url)
do {
let webURL = try container.decode(WebURL.self, forKey: .url)
if let url = URL(webURL) {
self.url = url
} else {
let s = try? container.decode(String.self, forKey: .url)
throw DecodingError.dataCorruptedError(forKey: .url, in: container, debugDescription: "unable to convert WebURL \(s?.debugDescription ?? "nil") to URL")
}
} catch {
self.url = try container.decode(URL.self, forKey: .url)
}
}
private enum CodingKeys: String, CodingKey {

View File

@ -12,14 +12,9 @@ import WebURLFoundationExtras
class URLTests: XCTestCase {
func testDecodeURL() {
XCTAssertNotNil(WebURL(URL(string: "https://xn--baw-joa.social/@unituebingen")!))
XCTAssertNotNil(WebURL("https://xn--baw-joa.social/@unituebingen"))
XCTAssertNotNil(URLComponents(string: "https://xn--baw-joa.social/test/é"))
XCTAssertNotNil(WebURL("https://xn--baw-joa.social/test/é"))
if #available(iOS 16.0, *) {
XCTAssertNotNil(try? URL.ParseStrategy().parse("https://xn--baw-joa.social/test/é"))
XCTAssertNotNil(try? URL.ParseStrategy().parse("http://見.香港/热狗/🌭"))
}
print(WebURL(URL(string: "https://xn--baw-joa.social/@unituebingen")!))
let url = WebURL("https://xn--baw-joa.social/@unituebingen")
print(url)
}
}

View File

@ -9,7 +9,6 @@
import Foundation
import CoreData
import Pachyderm
import WebURLFoundationExtras
@objc(SavedHashtag)
public final class SavedHashtag: NSManagedObject {
@ -33,6 +32,6 @@ extension SavedHashtag {
convenience init(hashtag: Hashtag, context: NSManagedObjectContext) {
self.init(context: context)
self.name = hashtag.name
self.url = URL(hashtag.url)!
self.url = hashtag.url
}
}

View File

@ -70,9 +70,7 @@ struct ComposeAttachmentsList: View {
.listRowInsets(EdgeInsets(top: cellPadding / 2, leading: cellPadding / 2, bottom: cellPadding / 2, trailing: cellPadding / 2))
}
.listStyle(PlainListStyle())
// todo: scrollDisabled doesn't remove the need for manually calculating the frame height
.frame(height: totalListHeight)
.scrollDisabledIfAvailable(totalHeight: totalListHeight)
.onAppear(perform: self.didAppear)
.onReceive(draft.$attachments, perform: self.attachmentsChanged)
}
@ -214,16 +212,6 @@ fileprivate extension View {
self
}
}
@available(iOS, obsoleted: 16.0)
@ViewBuilder
func scrollDisabledIfAvailable(totalHeight: CGFloat) -> some View {
if #available(iOS 16.0, *) {
self.scrollDisabled(true)
} else {
self.frame(height: totalHeight)
}
}
}
@available(iOS 16.0, *)

View File

@ -10,7 +10,6 @@ import UIKit
import Combine
import Pachyderm
import CoreData
import WebURLFoundationExtras
class ExploreViewController: UIViewController, UICollectionViewDelegate {
@ -583,10 +582,7 @@ extension ExploreViewController: UICollectionViewDragDelegate {
activity.displaysAuxiliaryScene = true
provider = NSItemProvider(object: activity)
case let .savedHashtag(hashtag):
guard let url = URL(hashtag.url) else {
return []
}
provider = NSItemProvider(object: url as NSURL)
provider = NSItemProvider(object: hashtag.url as NSURL)
if let activity = UserActivityManager.showTimelineActivity(timeline: .tag(hashtag: hashtag.name), accountID: accountID) {
activity.displaysAuxiliaryScene = true
provider.registerObject(activity, visibility: .all)

View File

@ -8,7 +8,6 @@
import UIKit
import Pachyderm
import WebURLFoundationExtras
class TrendingHashtagsViewController: UIViewController {
@ -106,11 +105,10 @@ extension TrendingHashtagsViewController: UICollectionViewDelegate {
extension TrendingHashtagsViewController: UICollectionViewDragDelegate {
func collectionView(_ collectionView: UICollectionView, itemsForBeginning session: UIDragSession, at indexPath: IndexPath) -> [UIDragItem] {
guard let item = dataSource.itemIdentifier(for: indexPath),
case let .tag(hashtag) = item,
let url = URL(hashtag.url) else {
case let .tag(hashtag) = item else {
return []
}
let provider = NSItemProvider(object: url as NSURL)
let provider = NSItemProvider(object: hashtag.url as NSURL)
if let activity = UserActivityManager.showTimelineActivity(timeline: .tag(hashtag: hashtag.name), accountID: mastodonController.accountInfo!.id) {
activity.displaysAuxiliaryScene = true
provider.registerObject(activity, visibility: .all)

View File

@ -9,7 +9,6 @@
import UIKit
import Pachyderm
import SafariServices
import WebURLFoundationExtras
class SearchViewController: UIViewController {
@ -296,10 +295,7 @@ extension SearchViewController: UICollectionViewDragDelegate {
}
switch item {
case let .tag(hashtag):
guard let url = URL(hashtag.url) else {
return []
}
let provider = NSItemProvider(object: url as NSURL)
let provider = NSItemProvider(object: hashtag.url as NSURL)
if let activity = UserActivityManager.showTimelineActivity(timeline: .tag(hashtag: hashtag.name), accountID: mastodonController.accountInfo!.id) {
activity.displaysAuxiliaryScene = true
provider.registerObject(activity, visibility: .all)

View File

@ -9,7 +9,6 @@
import UIKit
import SafariServices
import Pachyderm
import WebURLFoundationExtras
protocol MenuActionProvider: AnyObject {
var navigationDelegate: TuskerNavigationDelegate? { get }
@ -117,12 +116,7 @@ extension MenuActionProvider {
actionsSection = []
}
let shareSection: [UIMenuElement]
if let url = URL(hashtag.url) {
shareSection = actionsForURL(url, sourceView: sourceView)
} else {
shareSection = []
}
let shareSection = actionsForURL(hashtag.url, sourceView: sourceView)
return [
UIMenu(title: "", image: nil, identifier: nil, options: [.displayInline], children: shareSection),

View File

@ -270,9 +270,8 @@ class ContentTextView: LinkTextView, BaseEmojiLabel {
extension ContentTextView: UITextViewDelegate {
func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool {
// generally disable the text view's link interactions, we handle tapping links ourself with a gesture recognizer
// the builtin data detectors use the x-apple-data-detectors scheme, and we allow the text view to handle those itself
return URL.scheme == "x-apple-data-detectors"
// disable the text view's link interactions, we handle tapping links ourself with a gesture recognizer
return false
}
}

View File

@ -50,10 +50,6 @@ class ConversationMainStatusTableViewCell: BaseStatusTableViewCell {
]
contentTextView.defaultFont = .systemFont(ofSize: 18)
contentTextView.dataDetectorTypes = [.flightNumber, .address, .shipmentTrackingNumber, .phoneNumber]
if #available(iOS 16.0, *) {
contentTextView.dataDetectorTypes.formUnion([.money, .physicalValue])
}
profileDetailContainerView.addInteraction(UIContextMenuInteraction(delegate: self))

View File

@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="21179.7" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="20037" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21169.4"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="20020"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="System colors in document resources" minToolsVersion="11.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
@ -108,7 +108,7 @@
<action selector="collapseButtonPressed" destination="iN0-l3-epB" eventType="touchUpInside" id="JaH-xX-UOD"/>
</connections>
</button>
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" scrollEnabled="NO" delaysContentTouches="NO" editable="NO" textAlignment="natural" selectable="NO" translatesAutoresizingMaskIntoConstraints="NO" id="waJ-f5-LKv" customClass="StatusContentTextView" customModule="Tusker" customModuleProvider="target">
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" scrollEnabled="NO" delaysContentTouches="NO" editable="NO" selectable="NO" translatesAutoresizingMaskIntoConstraints="NO" id="waJ-f5-LKv" customClass="StatusContentTextView" customModule="Tusker" customModuleProvider="target">
<rect key="frame" x="0.0" y="83" width="277" height="82.5"/>
<string key="text">Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Nam liber te conscient to factor tum poen legum odioque civiuda.</string>
<color key="textColor" systemColor="labelColor"/>
@ -272,14 +272,14 @@
</view>
</objects>
<resources>
<image name="arrowshape.turn.up.left.fill" catalog="system" width="128" height="104"/>
<image name="chevron.down" catalog="system" width="128" height="70"/>
<image name="arrowshape.turn.up.left.fill" catalog="system" width="128" height="106"/>
<image name="chevron.down" catalog="system" width="128" height="72"/>
<image name="ellipsis" catalog="system" width="128" height="37"/>
<image name="pin.fill" catalog="system" width="116" height="128"/>
<image name="pin.fill" catalog="system" width="119" height="128"/>
<image name="repeat" catalog="system" width="128" height="98"/>
<image name="star.fill" catalog="system" width="128" height="116"/>
<systemColor name="labelColor">
<color red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</systemColor>
<systemColor name="secondaryLabelColor">
<color red="0.23529411764705882" green="0.23529411764705882" blue="0.2627450980392157" alpha="0.59999999999999998" colorSpace="custom" customColorSpace="sRGB"/>

View File

@ -8,7 +8,6 @@
import UIKit
import Pachyderm
import WebURLFoundationExtras
class StatusContentTextView: ContentTextView {
@ -28,7 +27,7 @@ class StatusContentTextView: ContentTextView {
let status = mastodonController.persistentContainer.status(for: statusID) {
mention = status.mentions.first { (mention) in
// Mastodon and Pleroma include the @ in the <a> text, GNU Social does not
(text.dropFirst() == mention.username || text == mention.username) && url.host == mention.url.host!.serialized
(text.dropFirst() == mention.username || text == mention.username) && url.host == mention.url.host!
}
} else {
mention = nil
@ -42,7 +41,7 @@ class StatusContentTextView: ContentTextView {
let mastodonController = mastodonController,
let status = mastodonController.persistentContainer.status(for: statusID) {
hashtag = status.hashtags.first { (hashtag) in
URL(hashtag.url) == url
hashtag.url == url
}
} else {
hashtag = nil