Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New feature Swipe #44

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions Examples/UIComponentExample.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,14 @@
B1CC3F7026789E1F005BCE8C /* CardViewController3.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1CC3F6F26789E1F005BCE8C /* CardViewController3.swift */; };
B1CC3F7226789F07005BCE8C /* AddCardButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1CC3F7126789F07005BCE8C /* AddCardButton.swift */; };
B1CC3F7426789F3D005BCE8C /* CardData.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1CC3F7326789F3D005BCE8C /* CardData.swift */; };
F80A67B22BCD2236006FACFD /* SwipeExampleData.swift in Sources */ = {isa = PBXBuildFile; fileRef = F80A67B12BCD2236006FACFD /* SwipeExampleData.swift */; };
F80A67B42BCD248C006FACFD /* SwipeExampleComponents.swift in Sources */ = {isa = PBXBuildFile; fileRef = F80A67B32BCD248C006FACFD /* SwipeExampleComponents.swift */; };
F839CC0E26A90DDF00392BCE /* IntroductionCard.swift in Sources */ = {isa = PBXBuildFile; fileRef = F839CC0D26A90DDF00392BCE /* IntroductionCard.swift */; };
F858D54026B9459E00410219 /* GalleryComponents.swift in Sources */ = {isa = PBXBuildFile; fileRef = F858D53D26B9459E00410219 /* GalleryComponents.swift */; };
F858D54126B9459E00410219 /* GalleryLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = F858D53E26B9459E00410219 /* GalleryLayout.swift */; };
F858D54226B9459E00410219 /* GalleryViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F858D53F26B9459E00410219 /* GalleryViewController.swift */; };
F88E832226A3E6FA009E7720 /* FlexLayoutViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F88E832126A3E6FA009E7720 /* FlexLayoutViewController.swift */; };
F8D885CF2BC278280003DBA8 /* SwipeActionsExample.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8D885CE2BC278280003DBA8 /* SwipeActionsExample.swift */; };
F8E3DD1426A7BC5F0062E58F /* HorizontalCardItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8E3DD1126A7BC5F0062E58F /* HorizontalCardItem.swift */; };
F8E3DD1526A7BC5F0062E58F /* UserProfile.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8E3DD1226A7BC5F0062E58F /* UserProfile.swift */; };
F8E3DD1626A7BC5F0062E58F /* ComplexLayoutViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8E3DD1326A7BC5F0062E58F /* ComplexLayoutViewController.swift */; };
Expand Down Expand Up @@ -72,11 +75,14 @@
B1CC3F6F26789E1F005BCE8C /* CardViewController3.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CardViewController3.swift; sourceTree = "<group>"; };
B1CC3F7126789F07005BCE8C /* AddCardButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddCardButton.swift; sourceTree = "<group>"; };
B1CC3F7326789F3D005BCE8C /* CardData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CardData.swift; sourceTree = "<group>"; };
F80A67B12BCD2236006FACFD /* SwipeExampleData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwipeExampleData.swift; sourceTree = "<group>"; };
F80A67B32BCD248C006FACFD /* SwipeExampleComponents.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwipeExampleComponents.swift; sourceTree = "<group>"; };
F839CC0D26A90DDF00392BCE /* IntroductionCard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IntroductionCard.swift; sourceTree = "<group>"; };
F858D53D26B9459E00410219 /* GalleryComponents.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GalleryComponents.swift; sourceTree = "<group>"; };
F858D53E26B9459E00410219 /* GalleryLayout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GalleryLayout.swift; sourceTree = "<group>"; };
F858D53F26B9459E00410219 /* GalleryViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GalleryViewController.swift; sourceTree = "<group>"; };
F88E832126A3E6FA009E7720 /* FlexLayoutViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FlexLayoutViewController.swift; sourceTree = "<group>"; };
F8D885CE2BC278280003DBA8 /* SwipeActionsExample.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwipeActionsExample.swift; sourceTree = "<group>"; };
F8E3DD1126A7BC5F0062E58F /* HorizontalCardItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HorizontalCardItem.swift; sourceTree = "<group>"; };
F8E3DD1226A7BC5F0062E58F /* UserProfile.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserProfile.swift; sourceTree = "<group>"; };
F8E3DD1326A7BC5F0062E58F /* ComplexLayoutViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ComplexLayoutViewController.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -182,6 +188,7 @@
B1CC3F6C267800B9005BCE8C /* Examples */ = {
isa = PBXGroup;
children = (
F8D885CC2BC277E10003DBA8 /* SwipeActions */,
B1CC3F6A2678009C005BCE8C /* AsyncImage */,
B1CC3F692678008F005BCE8C /* Card */,
F8E3DD0F26A7BC5F0062E58F /* Complex layout */,
Expand All @@ -194,6 +201,22 @@
path = Examples;
sourceTree = "<group>";
};
F80A67AF2BCD2218006FACFD /* Components */ = {
isa = PBXGroup;
children = (
F80A67B32BCD248C006FACFD /* SwipeExampleComponents.swift */,
);
path = Components;
sourceTree = "<group>";
};
F80A67B02BCD221F006FACFD /* Data */ = {
isa = PBXGroup;
children = (
F80A67B12BCD2236006FACFD /* SwipeExampleData.swift */,
);
path = Data;
sourceTree = "<group>";
};
F858D53B26B9459E00410219 /* Gallery Example */ = {
isa = PBXGroup;
children = (
Expand All @@ -220,6 +243,16 @@
path = "Flex Layout";
sourceTree = "<group>";
};
F8D885CC2BC277E10003DBA8 /* SwipeActions */ = {
isa = PBXGroup;
children = (
F80A67B02BCD221F006FACFD /* Data */,
F80A67AF2BCD2218006FACFD /* Components */,
F8D885CE2BC278280003DBA8 /* SwipeActionsExample.swift */,
);
path = SwipeActions;
sourceTree = "<group>";
};
F8E3DD0F26A7BC5F0062E58F /* Complex layout */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -323,10 +356,12 @@
B1CC3F7226789F07005BCE8C /* AddCardButton.swift in Sources */,
F8E3DD1526A7BC5F0062E58F /* UserProfile.swift in Sources */,
F839CC0E26A90DDF00392BCE /* IntroductionCard.swift in Sources */,
F8D885CF2BC278280003DBA8 /* SwipeActionsExample.swift in Sources */,
F8E3DD1626A7BC5F0062E58F /* ComplexLayoutViewController.swift in Sources */,
B1B079EE26AB398E003BEAFB /* WaterfallLayoutViewController.swift in Sources */,
B1CC3F632677FCFD005BCE8C /* CardViewController.swift in Sources */,
F88E832226A3E6FA009E7720 /* FlexLayoutViewController.swift in Sources */,
F80A67B22BCD2236006FACFD /* SwipeExampleData.swift in Sources */,
F858D54026B9459E00410219 /* GalleryComponents.swift in Sources */,
B1CC3F652677FD99005BCE8C /* ComponentViewController.swift in Sources */,
B1CC3F672677FF79005BCE8C /* AsyncImageViewController.swift in Sources */,
Expand All @@ -342,6 +377,7 @@
A304892821C347010026EDA7 /* AppDelegate.swift in Sources */,
B1CC3F7426789F3D005BCE8C /* CardData.swift in Sources */,
B1CC3F7026789E1F005BCE8C /* CardViewController3.swift in Sources */,
F80A67B42BCD248C006FACFD /* SwipeExampleComponents.swift in Sources */,
B1CC3F6E26789C55005BCE8C /* CardViewController2.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down Expand Up @@ -491,6 +527,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = "";
INFOPLIST_FILE = "$(SRCROOT)/UIComponentExample/Supporting Files/Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
LD_RUNPATH_SEARCH_PATHS = (
Expand All @@ -510,6 +547,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = "";
INFOPLIST_FILE = "$(SRCROOT)/UIComponentExample/Supporting Files/Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
LD_RUNPATH_SEARCH_PATHS = (
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
// Created by y H on 2024/4/15.

import UIComponent
import UIKit

extension SwipeActionComponent {
static func rounded(horizontalEdge: SwipeHorizontalEdge, cornerRadius: CGFloat = 15) -> Self {
self.init(identifier: UUID().uuidString, horizontalEdge: horizontalEdge) {
Text("Test")
.textColor(.secondaryLabel)
.inset(h: 20)
} background: {
ViewComponent()
.backgroundColor(.systemGroupedBackground)
.with(\.layer.cornerRadius, cornerRadius)
.with(\.layer.cornerCurve, .continuous)
} alert: {
Space()
} configHighlightView: { highlightView, isHighlighted in
UIView.performWithoutAnimation {
highlightView.layer.cornerRadius = cornerRadius
}
highlightView.backgroundColor = .black.withAlphaComponent(isHighlighted ? 0.3 : 0)
} actionHandler: { completion, action, form in
completion(.swipeFull(nil))
}


}
}

extension SwipeActionsExample {

struct Group: ComponentBuilder {
let title: String
let body: [any Component]
init(title: String, @ComponentArrayBuilder _ body: () -> [any Component]) {
self.title = title
self.body = body()
}
func build() -> some Component {
VStack(alignItems: .stretch) {
Text(title, font: UIFont.preferredFont(forTextStyle: .headline))
.inset(top: 15, left: 15, bottom: 10, right: 0)
VStack(alignItems: .stretch) {
for (offset, component) in body.enumerated() {
var maskedCorners: CACornerMask {
if body.count == 1 {
return [.layerMinXMaxYCorner, .layerMaxXMaxYCorner, .layerMinXMinYCorner, .layerMaxXMinYCorner]
} else if offset == body.count - 1 {
return [.layerMinXMaxYCorner, .layerMaxXMaxYCorner]
} else if offset == 0 {
return [.layerMinXMinYCorner, .layerMaxXMinYCorner]
} else {
return []
}
}
if maskedCorners.isEmpty {
component
} else {
component
.view()
.clipsToBounds(true)
.with(\.layer.cornerRadius, 15)
.with(\.layer.cornerCurve, .continuous)
.with(\.layer.maskedCorners, maskedCorners)
}
}
}
.background {
Space()
.backgroundColor(.secondarySystemGroupedBackground)
.with(\.layer.cornerRadius, 15)
.with(\.layer.cornerCurve, .continuous)
}
}
.size(width: .fill)
}
}

struct Cell: ComponentBuilder {
let title: String
func build() -> some Component {
HStack(alignItems: .center) {
Text(title, font: .preferredFont(forTextStyle: .body))
}
.inset(15)
.minSize(height: 44)
}
}
struct Email: ComponentBuilder {
let data: EmailData
func build() -> some Component {
HStack(alignItems: .stretch) {
VStack(justifyContent: .start, alignItems: .center) {
if data.unread {
Space(width: 10, height: 10)
.backgroundColor(UIColor(red: 0.008, green: 0.475, blue: 0.996, alpha: 1.0))
.roundedCorner()
.inset(top: 5)
}
}
.size(width: 30)
VStack(spacing: 2) {
HStack {
Text(data.from, font: .systemFont(ofSize: 16, weight: .semibold), numberOfLines: 1, lineBreakMode: .byTruncatingTail)
.flex()
HStack(spacing: 5, alignItems: .center) {
Text(data.date.formatted(), font: .systemFont(ofSize: 16, weight: .regular))
.textColor(.secondaryLabel)
Image(systemName: "chevron.right")
.tintColor(.secondaryLabel)
.transform(.identity.scaledBy(x: 0.8, y: 0.8))
}
}
Text(data.subject, font: .systemFont(ofSize: 15, weight: .regular), numberOfLines: 1, lineBreakMode: .byTruncatingTail)
Text(data.body, font: .systemFont(ofSize: 15, weight: .regular), numberOfLines: 2, lineBreakMode: .byTruncatingTail)
.textColor(.secondaryLabel)
}
.flex()

}
.size(width: .fill)
.inset(left: 0, rest: 10)

}
}

func defaultSectionTitle(_ title: String) -> some Component {
Text(title, font: UIFont.preferredFont(forTextStyle: .largeTitle))
.inset(h: 30, v: 20)
}

func defaultSubheadlineTitle(_ title: String) -> some Component {
Text(title, font: UIFont.preferredFont(forTextStyle: .title2))
.textColor(.label)
.inset(h: 10, v: 10)
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// Created by y H on 2024/4/15.

import Foundation
import UIComponent

extension SwipeActionsExample {
var defaultActions: [any SwipeAction] {
[
SwipeActionComponent(horizontalEdge: .right, backgroundColor: .systemRed, body: {
Text("First")
.textColor(.white)
.inset(10)
}, actionHandler: { completion, action, form in
completion(.close)
}),
SwipeActionComponent(horizontalEdge: .right, backgroundColor: .systemBlue, body: {
Text("Second")
.textColor(.white)
.inset(10)
}, actionHandler: { completion, action, form in
completion(.close)
})
]
}
}

struct EmailData: Equatable {
var from: String
var subject: String
var body: String
var date: Date
var unread: Bool

init(from: String, subject: String, body: String, date: Date, unread: Bool = Bool.random()) {
self.from = from
self.subject = subject
self.body = body
self.date = date
self.unread = unread
}

static var mockDatas: [EmailData] {
[
EmailData(from: "Realm", subject: "Video: Operators and Strong Opinions with Erica Sadun", body: "Swift operators are flexible and powerful. They’re symbols that behave like functions, adopting a natural mathematical syntax, for example 1 + 2 versus add(1, 2). So why is it so important that you treat them like potential Swift Kryptonite? Erica Sadun discusses why your operators should be few, well-chosen, and heavily used. There’s even a fun interactive quiz! Play along with “Name That Operator!” and learn about an essential Swift best practice.", date: Calendar.now(addingDays: 0)),
EmailData(from: "The Pragmatic Bookstore", subject: "[Pragmatic Bookstore] Your eBook 'Swift Style' is ready for download", body: "Hello, The gerbils at the Pragmatic Bookstore have just finished hand-crafting your eBook of Swift Style. It's available for download at the following URL:", date: Calendar.now(addingDays: 0)),
EmailData(from: "Instagram", subject: "mrx, go live and send disappearing photos and videos", body: "Go Live and Send Disappearing Photos and Videos. We recently announced two updates: live video on Instagram Stories and disappearing photos and videos for groups and friends in Instagram Direct.", date: Calendar.now(addingDays: -1)),
EmailData(from: "Smithsonian Magazine", subject: "Exclusive Sneak Peek Inside | Untold Stories of the Civil War", body: "For the very first time, the Smithsonian showcases the treasures of its Civil War collections in Smithsonian Civil War. This 384-page, hardcover book takes readers inside the museum storerooms and vaults to learn the untold stories behind the Smithsonian's most fascinating and significant pieces, including many previously unseen relics and artifacts. With over 500 photographs and text from forty-nine curators, the Civil War comes alive.", date: Calendar.now(addingDays: -2)),
EmailData(from: "Apple News", subject: "How to Change Your Personality in 90 Days", body: "How to Change Your Personality. You are not stuck with yourself. New research shows that you can troubleshoot personality traits — in therapy.", date: Calendar.now(addingDays: -3)),
EmailData(from: "Wordpress", subject: "New WordPress Site", body: "Your new WordPress site has been successfully set up at: http://example.com. You can log in to the administrator account with the following information:", date: Calendar.now(addingDays: -4)),
EmailData(from: "IFTTT", subject: "See what’s new & notable on IFTTT", body: "See what’s new & notable on IFTTT. To disable these emails, sign in to manage your settings or unsubscribe.", date: Calendar.now(addingDays: -5)),
EmailData(from: "Westin Vacations", subject: "Your Westin exclusive expires January 11", body: "Last chance to book a captivating 5-day, 4-night vacation in Rancho Mirage for just $389. Learn more. No images? CLICK HERE", date: Calendar.now(addingDays: -6)),
EmailData(from: "Nugget Markets", subject: "Nugget Markets Weekly Specials Starting February 15, 2017", body: "Scan & Save. For this week’s Secret Special, let’s “brioche” the subject of breakfast. This Friday and Saturday, February 24–25, buy one loaf of Euro Classic Brioche and get one free! This light, soft, hand-braided buttery brioche loaf from France is perfect for an authentic French toast feast. Make Christmas morning extra special with our Signature Recipe for Crème Brûlée French Toast Soufflé!", date: Calendar.now(addingDays: -7)),
EmailData(from: "GeekDesk", subject: "We have some exciting things happening at GeekDesk!", body: "Wouldn't everyone be so much happier if we all owned GeekDesks?", date: Calendar.now(addingDays: -8)),
]
}
}

extension Calendar {
static func now(addingDays days: Int) -> Date {
return Date().addingTimeInterval(Double(days) * 60 * 60 * 24)
}
}
Loading
Loading