diff --git a/Packages/TuskerComponents/.gitignore b/Packages/TuskerComponents/.gitignore new file mode 100644 index 00000000..3b298120 --- /dev/null +++ b/Packages/TuskerComponents/.gitignore @@ -0,0 +1,9 @@ +.DS_Store +/.build +/Packages +/*.xcodeproj +xcuserdata/ +DerivedData/ +.swiftpm/config/registries.json +.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata +.netrc diff --git a/Packages/TuskerComponents/Package.swift b/Packages/TuskerComponents/Package.swift new file mode 100644 index 00000000..a0bd020b --- /dev/null +++ b/Packages/TuskerComponents/Package.swift @@ -0,0 +1,31 @@ +// swift-tools-version: 5.7 +// The swift-tools-version declares the minimum version of Swift required to build this package. + +import PackageDescription + +let package = Package( + name: "TuskerComponents", + platforms: [ + .iOS(.v15), + ], + products: [ + // Products define the executables and libraries a package produces, and make them visible to other packages. + .library( + name: "TuskerComponents", + targets: ["TuskerComponents"]), + ], + dependencies: [ + // Dependencies declare other packages that this package depends on. + // .package(url: /* package url */, from: "1.0.0"), + ], + targets: [ + // Targets are the basic building blocks of a package. A target can define a module or a test suite. + // Targets can depend on other targets in this package, and on products in packages this package depends on. + .target( + name: "TuskerComponents", + dependencies: []), + .testTarget( + name: "TuskerComponentsTests", + dependencies: ["TuskerComponents"]), + ] +) diff --git a/Packages/TuskerComponents/README.md b/Packages/TuskerComponents/README.md new file mode 100644 index 00000000..11206816 --- /dev/null +++ b/Packages/TuskerComponents/README.md @@ -0,0 +1,3 @@ +# TuskerComponents + +A description of this package. diff --git a/Tusker/Views/MenuPicker.swift b/Packages/TuskerComponents/Sources/TuskerComponents/MenuPicker.swift similarity index 73% rename from Tusker/Views/MenuPicker.swift rename to Packages/TuskerComponents/Sources/TuskerComponents/MenuPicker.swift index 03dc3c44..21c0c8e9 100644 --- a/Tusker/Views/MenuPicker.swift +++ b/Packages/TuskerComponents/Sources/TuskerComponents/MenuPicker.swift @@ -1,6 +1,6 @@ // // MenuPicker.swift -// Tusker +// TuskerComponents // // Created by Shadowfacts on 11/7/22. // Copyright © 2022 Shadowfacts. All rights reserved. @@ -8,25 +8,31 @@ import SwiftUI -struct MenuPicker: UIViewRepresentable { - typealias UIViewType = UIButton +public struct MenuPicker: UIViewRepresentable { + public typealias UIViewType = UIButton @Binding var selection: Value let options: [Option] - var buttonStyle: ButtonStyle = .labelAndIcon + var buttonStyle: ButtonStyle private var selectedOption: Option { options.first(where: { $0.value == selection })! } - func makeUIView(context: Context) -> UIButton { + public init(selection: Binding, options: [Option], buttonStyle: ButtonStyle = .labelAndIcon) { + self._selection = selection + self.options = options + self.buttonStyle = buttonStyle + } + + public func makeUIView(context: Context) -> UIButton { let button = UIButton() button.showsMenuAsPrimaryAction = true button.setContentHuggingPriority(.required, for: .horizontal) return button } - func updateUIView(_ button: UIButton, context: Context) { + public func updateUIView(_ button: UIButton, context: Context) { var config = UIButton.Configuration.borderless() if #available(iOS 16.0, *) { config.indicator = .popup @@ -49,14 +55,14 @@ struct MenuPicker: UIViewRepresentable { button.isPointerInteractionEnabled = buttonStyle == .iconOnly } - struct Option { - let value: Value - let title: String - let subtitle: String? - let image: UIImage? - let accessibilityLabel: String? + public struct Option { + public let value: Value + public let title: String + public let subtitle: String? + public let image: UIImage? + public let accessibilityLabel: String? - init(value: Value, title: String, subtitle: String? = nil, image: UIImage? = nil, accessibilityLabel: String? = nil) { + public init(value: Value, title: String, subtitle: String? = nil, image: UIImage? = nil, accessibilityLabel: String? = nil) { self.value = value self.title = title self.subtitle = subtitle @@ -65,7 +71,7 @@ struct MenuPicker: UIViewRepresentable { } } - enum ButtonStyle { + public enum ButtonStyle { case labelAndIcon, labelOnly, iconOnly var hasLabel: Bool { diff --git a/Tusker.xcodeproj/project.pbxproj b/Tusker.xcodeproj/project.pbxproj index dcf4216a..a967bb6e 100644 --- a/Tusker.xcodeproj/project.pbxproj +++ b/Tusker.xcodeproj/project.pbxproj @@ -117,6 +117,7 @@ D6311C5025B3765B00B27539 /* ImageDataCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6311C4F25B3765B00B27539 /* ImageDataCache.swift */; }; D6333B372137838300CE884A /* AttributedString+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6333B362137838300CE884A /* AttributedString+Helpers.swift */; }; D6333B792139AEFD00CE884A /* Date+TimeAgo.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6333B782139AEFD00CE884A /* Date+TimeAgo.swift */; }; + D635237129B78A7D009ED5E7 /* TuskerComponents in Frameworks */ = {isa = PBXBuildFile; productRef = D635237029B78A7D009ED5E7 /* TuskerComponents */; }; D63661C02381C144004B9E16 /* PreferencesNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D63661BF2381C144004B9E16 /* PreferencesNavigationController.swift */; }; D6370B9C24421FF30092A7FF /* Tusker.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = D6370B9A24421FF30092A7FF /* Tusker.xcdatamodeld */; }; D63CC702290EC0B8000E19DE /* Sentry in Frameworks */ = {isa = PBXBuildFile; productRef = D63CC701290EC0B8000E19DE /* Sentry */; }; @@ -180,7 +181,6 @@ D667E5F82135C3040057A976 /* Mastodon+Equatable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D667E5F72135C3040057A976 /* Mastodon+Equatable.swift */; }; D66A77BB233838DC0058F1EC /* UIFont+Traits.swift in Sources */ = {isa = PBXBuildFile; fileRef = D66A77BA233838DC0058F1EC /* UIFont+Traits.swift */; }; D66C900B28DAB7FD00217BF2 /* TimelineViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D66C900A28DAB7FD00217BF2 /* TimelineViewController.swift */; }; - D673ACCE2919E74200D6F8B0 /* MenuPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = D673ACCD2919E74200D6F8B0 /* MenuPicker.swift */; }; D674A50927F9128D00BA03AC /* Pachyderm in Frameworks */ = {isa = PBXBuildFile; productRef = D674A50827F9128D00BA03AC /* Pachyderm */; }; D677284824ECBCB100C732D3 /* ComposeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D677284724ECBCB100C732D3 /* ComposeView.swift */; }; D677284A24ECBDF400C732D3 /* ComposeCurrentAccount.swift in Sources */ = {isa = PBXBuildFile; fileRef = D677284924ECBDF400C732D3 /* ComposeCurrentAccount.swift */; }; @@ -599,7 +599,6 @@ D66A77BA233838DC0058F1EC /* UIFont+Traits.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIFont+Traits.swift"; sourceTree = ""; }; D66C900A28DAB7FD00217BF2 /* TimelineViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineViewController.swift; sourceTree = ""; }; D671A6BE299DA96100A81FEA /* Tusker-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Tusker-Bridging-Header.h"; sourceTree = ""; }; - D673ACCD2919E74200D6F8B0 /* MenuPicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuPicker.swift; sourceTree = ""; }; D674A50727F910F300BA03AC /* Pachyderm */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = Pachyderm; path = Packages/Pachyderm; sourceTree = ""; }; D677284724ECBCB100C732D3 /* ComposeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeView.swift; sourceTree = ""; }; D677284924ECBDF400C732D3 /* ComposeCurrentAccount.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeCurrentAccount.swift; sourceTree = ""; }; @@ -710,6 +709,7 @@ D6BC9DB4232D4CE3002CA326 /* NotificationsMode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationsMode.swift; sourceTree = ""; }; D6BC9DD6232D7811002CA326 /* TimelinesPageViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelinesPageViewController.swift; sourceTree = ""; }; D6BC9DD9232D8BE5002CA326 /* SearchResultsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchResultsViewController.swift; sourceTree = ""; }; + D6BD395C29B789D5005FFD2B /* TuskerComponents */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = TuskerComponents; path = Packages/TuskerComponents; sourceTree = ""; }; D6BEA243291A0C83002F4D01 /* Duckable */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = Duckable; path = Packages/Duckable; sourceTree = ""; }; D6BEA246291A0F2D002F4D01 /* Duckable+Root.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Duckable+Root.swift"; sourceTree = ""; }; D6BEA248291C6118002F4D01 /* DraftsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DraftsView.swift; sourceTree = ""; }; @@ -812,6 +812,7 @@ buildActionMask = 2147483647; files = ( D6FA94E129B52898006AAC51 /* InstanceFeatures in Frameworks */, + D635237129B78A7D009ED5E7 /* TuskerComponents in Frameworks */, D674A50927F9128D00BA03AC /* Pachyderm in Frameworks */, D659F35E2953A212002D944A /* TTTKit in Frameworks */, D6B0026E29B5248800C70BE2 /* UserAccounts in Frameworks */, @@ -1466,7 +1467,6 @@ D620483323D3801D008A63EF /* LinkTextView.swift */, D61A45E728DF477D002BE511 /* LoadingCollectionViewCell.swift */, D6262C9928D01C4B00390C1F /* LoadingTableViewCell.swift */, - D673ACCD2919E74200D6F8B0 /* MenuPicker.swift */, D68E6F58253C9969001A1B4C /* MultiSourceEmojiLabel.swift */, D627943A23A55BA600D38C68 /* NavigableTableViewCell.swift */, D6D7069F29466649000827ED /* ScrollingSegmentedControl.swift */, @@ -1541,6 +1541,7 @@ D68A76F22953915C001DA1B3 /* TTTKit */, D6B0026C29B5245400C70BE2 /* UserAccounts */, D6FA94DF29B52891006AAC51 /* InstanceFeatures */, + D6BD395C29B789D5005FFD2B /* TuskerComponents */, D6D4DDCE212518A000E1C4BB /* Tusker */, D6D4DDE3212518A200E1C4BB /* TuskerTests */, D6D4DDEE212518A200E1C4BB /* TuskerUITests */, @@ -1745,6 +1746,7 @@ D659F35D2953A212002D944A /* TTTKit */, D6B0026D29B5248800C70BE2 /* UserAccounts */, D6FA94E029B52898006AAC51 /* InstanceFeatures */, + D635237029B78A7D009ED5E7 /* TuskerComponents */, ); productName = Tusker; productReference = D6D4DDCC212518A000E1C4BB /* Tusker.app */; @@ -2081,7 +2083,6 @@ D6BEA249291C6118002F4D01 /* DraftsView.swift in Sources */, D61F75AD293AF39000C0B37F /* Filter+Helpers.swift in Sources */, D6531DEE246B81C9000F9538 /* GifvAttachmentView.swift in Sources */, - D673ACCE2919E74200D6F8B0 /* MenuPicker.swift in Sources */, D6370B9C24421FF30092A7FF /* Tusker.xcdatamodeld in Sources */, D601FA83297EEC3F00A8E8B5 /* SuggestedProfileCardCollectionViewCell.swift in Sources */, D691772E29AA5D420054D7EF /* UserActivityHandlingContext.swift in Sources */, @@ -2945,6 +2946,10 @@ isa = XCSwiftPackageProductDependency; productName = Pachyderm; }; + D635237029B78A7D009ED5E7 /* TuskerComponents */ = { + isa = XCSwiftPackageProductDependency; + productName = TuskerComponents; + }; D63CC701290EC0B8000E19DE /* Sentry */ = { isa = XCSwiftPackageProductDependency; package = D63CC700290EC0B8000E19DE /* XCRemoteSwiftPackageReference "sentry-cocoa" */; diff --git a/Tusker/Screens/Compose/ComposePollView.swift b/Tusker/Screens/Compose/ComposePollView.swift index 6fb187b6..467c8c21 100644 --- a/Tusker/Screens/Compose/ComposePollView.swift +++ b/Tusker/Screens/Compose/ComposePollView.swift @@ -7,6 +7,7 @@ // import SwiftUI +import TuskerComponents struct ComposePollView: View { private static let formatter: DateComponentsFormatter = { diff --git a/Tusker/Screens/Compose/ComposeToolbar.swift b/Tusker/Screens/Compose/ComposeToolbar.swift index f3b7ba8f..d16bd943 100644 --- a/Tusker/Screens/Compose/ComposeToolbar.swift +++ b/Tusker/Screens/Compose/ComposeToolbar.swift @@ -8,6 +8,7 @@ import SwiftUI import Pachyderm +import TuskerComponents struct ComposeToolbar: View { static let height: CGFloat = 44 diff --git a/Tusker/Screens/Customize Timelines/EditFilterView.swift b/Tusker/Screens/Customize Timelines/EditFilterView.swift index 12e3972f..26cdb64f 100644 --- a/Tusker/Screens/Customize Timelines/EditFilterView.swift +++ b/Tusker/Screens/Customize Timelines/EditFilterView.swift @@ -8,6 +8,7 @@ import SwiftUI import Pachyderm +import TuskerComponents struct EditFilterView: View { private static let expiresInOptions: [MenuPicker.Option] = { diff --git a/Tusker/Screens/Mute/MuteAccountView.swift b/Tusker/Screens/Mute/MuteAccountView.swift index af33fb12..e6903b97 100644 --- a/Tusker/Screens/Mute/MuteAccountView.swift +++ b/Tusker/Screens/Mute/MuteAccountView.swift @@ -8,6 +8,7 @@ import SwiftUI import Pachyderm +import TuskerComponents struct MuteAccountView: View { private static let durationOptions: [MenuPicker.Option] = {