├── .swift-version
├── Assets
└── code.png
├── .swiftlint.yml
├── .swiftpm
└── xcode
│ └── package.xcworkspace
│ └── contents.xcworkspacedata
├── Sources
└── SlidableImage
│ ├── Constants.swift
│ ├── Triangle.swift
│ ├── Arrows.swift
│ └── SlidableImage.swift
├── .github
└── workflows
│ ├── PublishDocumentation.yml
│ ├── swiftlint.yml
│ └── ContinuousIntegration.yml
├── Package.swift
├── LICENSE
├── README.md
└── .gitignore
/.swift-version:
--------------------------------------------------------------------------------
1 | 5.5
2 |
3 |
--------------------------------------------------------------------------------
/Assets/code.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/quver/SlidableImage/HEAD/Assets/code.png
--------------------------------------------------------------------------------
/.swiftlint.yml:
--------------------------------------------------------------------------------
1 | disabled_rules:
2 | - trailing_whitespace
3 | line_length: 140
4 | excluded:
5 | - Sources
6 | - SlidableImage
7 | - SlidableImageTests
8 | excluded:
9 | - Pods
10 |
--------------------------------------------------------------------------------
/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Sources/SlidableImage/Constants.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Constants.swift
3 | // SlidableImage
4 | //
5 | // Created by Pawel Bednorz on 02/02/2025.
6 | //
7 |
8 | import SwiftUI
9 |
10 | enum Constants {
11 | static let arrowSize: CGFloat = 64
12 | }
13 |
--------------------------------------------------------------------------------
/.github/workflows/PublishDocumentation.yml:
--------------------------------------------------------------------------------
1 | name: PublishDocumentation
2 |
3 | on:
4 | release:
5 | types: [published]
6 |
7 | jobs:
8 | deploy_docs:
9 | runs-on: macOS-latest
10 | steps:
11 | - uses: actions/checkout@v1
12 | - name: Publish Jazzy Docs
13 | uses: steven0351/publish-jazzy-docs@v1.1.2
14 | with:
15 | personal_access_token: ${{ secrets.ACCESS_TOKEN }}
--------------------------------------------------------------------------------
/.github/workflows/swiftlint.yml:
--------------------------------------------------------------------------------
1 | name: SwiftLint
2 |
3 | on:
4 | pull_request:
5 | paths:
6 | - '.github/workflows/SwiftLint.yml'
7 | - '.swiftlint.yml'
8 | - '**/*.swift'
9 |
10 | jobs:
11 | SwiftLint:
12 | runs-on: ubuntu-latest
13 | steps:
14 | - uses: actions/checkout@v1
15 | - name: GitHub Action for SwiftLint
16 | uses: norio-nomura/action-swiftlint@3.2.1
17 |
--------------------------------------------------------------------------------
/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version:5.10.0
2 |
3 | import PackageDescription
4 |
5 | let package = Package(
6 | name: "SlidableImage",
7 | platforms: [
8 | .iOS(.v15),
9 | .macOS(.v12)
10 | ],
11 | products: [
12 | .library(
13 | name: "SlidableImage",
14 | targets: ["SlidableImage"]
15 | )
16 | ],
17 | targets: [
18 | .target(name: "SlidableImage"),
19 |
20 | ]
21 | )
22 |
--------------------------------------------------------------------------------
/.github/workflows/ContinuousIntegration.yml:
--------------------------------------------------------------------------------
1 | name: iOS CI
2 |
3 | on:
4 | push:
5 | branches: [ master ]
6 | pull_request:
7 | branches: [ '*' ]
8 |
9 | jobs:
10 | build:
11 | name: Build and Test default scheme using any available iPhone simulator
12 | runs-on: macos-latest
13 |
14 | steps:
15 | - name: Checkout
16 | uses: actions/checkout@v2
17 | - name: Build
18 | run: |
19 | swift build --verbose
20 | shell: bash
--------------------------------------------------------------------------------
/Sources/SlidableImage/Triangle.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Triangle.swift
3 | // SlidableImage
4 | //
5 |
6 | import SwiftUI
7 |
8 | struct Triangle: Shape {
9 | func path(in rect: CGRect) -> Path {
10 | Path { path in
11 | path.move(to: CGPoint(x: rect.minX, y: rect.minY))
12 | path.addLine(to: CGPoint(x: rect.minX, y: rect.maxY))
13 | path.addLine(to: CGPoint(x: rect.maxX, y: rect.midY))
14 | path.closeSubpath()
15 | }
16 | }
17 | }
18 |
19 | struct Triangle_Previews: PreviewProvider {
20 | static var previews: some View {
21 | Triangle()
22 | .frame(width: 100, height: 100)
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) Paweł Bednorz
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 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # SlidableImage
2 | 
3 | []()
4 | [](https://swift.org/package-manager)
5 |
6 | Easy to use library for before & after images. One-line initialization and SwiftUI.
7 |
8 | ## Requirements
9 |
10 | - iOS 15
11 | - Swift 5
12 |
13 | ## Instalation
14 |
15 | This library support
16 |
17 | - Swift Package Manager
18 |
19 | ## Using
20 |
21 | 
22 |
23 | ### Constructor
24 |
25 | ```swfit
26 | init(@ViewBuilder arrows: @escaping () -> ArrowsIcon,
27 | @ViewBuilder leftView: @escaping () -> LeftView,
28 | @ViewBuilder rightView: @escaping () -> RightView)
29 | ```
30 |
31 | ### Arrows
32 |
33 | ```swift
34 | init(arrowColor: Color = .white, backgroundColor: Color = .gray)
35 | ```
36 |
37 | ## Author
38 |
39 | Paweł Bednorz, Quver
40 |
41 | ## License
42 |
43 | SlidableImage Lib and Slider graphic are available under the MIT license.
44 | Check the LICENSE file for more information.
45 |
--------------------------------------------------------------------------------
/Sources/SlidableImage/Arrows.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Arrows.swift
3 | // SlidableImage
4 | //
5 |
6 | import SwiftUI
7 |
8 | public struct Arrows: View {
9 | private let arrowColor: Color
10 | private let backgroundColor: Color
11 |
12 | public init(arrowColor: Color = .white, backgroundColor: Color = .gray) {
13 | self.arrowColor = arrowColor
14 | self.backgroundColor = backgroundColor
15 | }
16 |
17 | public var body: some View {
18 | HStack(spacing: 5) {
19 | Triangle()
20 | .fill(arrowColor)
21 | .frame(width: 20, height: Constants.arrowSize / 2)
22 | .rotationEffect(.degrees(180))
23 | Triangle()
24 | .fill(arrowColor)
25 | .frame(width: 20, height: Constants.arrowSize / 2)
26 | }
27 | .frame(width: Constants.arrowSize, height: Constants.arrowSize)
28 | .background(backgroundColor)
29 | .cornerRadius(Constants.arrowSize / 2)
30 | }
31 | }
32 |
33 | struct ArrowsPreview: PreviewProvider {
34 | static var previews: some View {
35 | VStack {
36 | Arrows()
37 | Arrows(arrowColor: .green, backgroundColor: .orange)
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/Sources/SlidableImage/SlidableImage.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SlidableImage.swift
3 | // SlidableImage
4 | //
5 |
6 | import SwiftUI
7 |
8 | public struct SlidableImage: View {
9 | @State private var location: CGPoint?
10 | private let arrows: () -> ArrowsIcon
11 | private let leftView: () -> LeftView
12 | private let rightView: () -> RightView
13 |
14 | public init(@ViewBuilder arrows: @escaping () -> ArrowsIcon,
15 | @ViewBuilder leftView: @escaping () -> LeftView,
16 | @ViewBuilder rightView: @escaping () -> RightView) {
17 | self.arrows = arrows
18 | self.leftView = leftView
19 | self.rightView = rightView
20 | }
21 |
22 | public var body: some View {
23 | GeometryReader { geometry in
24 | ZStack(alignment: .leading) {
25 | rightView()
26 | leftView()
27 | .mask {
28 | HStack {
29 | Color.black
30 | Spacer(minLength: maskSize(width: geometry.size.width))
31 | }
32 | }
33 |
34 | arrows()
35 | .frame(width: Constants.arrowSize, height: Constants.arrowSize)
36 | .padding(.leading, location?.x ?? geometry.size.width / 2 - Constants.arrowSize / 2)
37 | .gesture(
38 | DragGesture()
39 | .onChanged { value in
40 | guard value.location.x <= geometry.size.width - Constants.arrowSize else { return }
41 |
42 | location = CGPoint(x: value.location.x, y: geometry.size.height / 2)
43 | }
44 | )
45 | }
46 | }
47 | }
48 |
49 | private func maskSize(width: CGFloat) -> CGFloat {
50 | guard let location = location?.x else {
51 | return width / 2
52 | }
53 |
54 | return width - location - Constants.arrowSize / 2
55 | }
56 | }
57 |
58 | struct SlidableImagePreview: PreviewProvider {
59 | static var previews: some View {
60 | SlidableImage(arrows: { Arrows() },
61 | leftView: { Color.red },
62 | rightView: { Color.green })
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Created by https://www.toptal.com/developers/gitignore/api/xcode,macos,objective-c,swift,swiftpackagemanager,swiftpm
2 | # Edit at https://www.toptal.com/developers/gitignore?templates=xcode,macos,objective-c,swift,swiftpackagemanager,swiftpm
3 |
4 | ### macOS ###
5 | # General
6 | .DS_Store
7 | .AppleDouble
8 | .LSOverride
9 |
10 | # Icon must end with two \r
11 | Icon
12 |
13 |
14 | # Thumbnails
15 | ._*
16 |
17 | # Files that might appear in the root of a volume
18 | .DocumentRevisions-V100
19 | .fseventsd
20 | .Spotlight-V100
21 | .TemporaryItems
22 | .Trashes
23 | .VolumeIcon.icns
24 | .com.apple.timemachine.donotpresent
25 |
26 | # Directories potentially created on remote AFP share
27 | .AppleDB
28 | .AppleDesktop
29 | Network Trash Folder
30 | Temporary Items
31 | .apdisk
32 |
33 | ### macOS Patch ###
34 | # iCloud generated files
35 | *.icloud
36 |
37 | ### Objective-C ###
38 | # Xcode
39 | #
40 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
41 |
42 | ## User settings
43 | xcuserdata/
44 |
45 | ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9)
46 | *.xcscmblueprint
47 | *.xccheckout
48 |
49 | ## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4)
50 | build/
51 | DerivedData/
52 | *.moved-aside
53 | *.pbxuser
54 | !default.pbxuser
55 | *.mode1v3
56 | !default.mode1v3
57 | *.mode2v3
58 | !default.mode2v3
59 | *.perspectivev3
60 | !default.perspectivev3
61 |
62 | ## Obj-C/Swift specific
63 | *.hmap
64 |
65 | ## App packaging
66 | *.ipa
67 | *.dSYM.zip
68 | *.dSYM
69 |
70 | # CocoaPods
71 | # We recommend against adding the Pods directory to your .gitignore. However
72 | # you should judge for yourself, the pros and cons are mentioned at:
73 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
74 | # Pods/
75 | # Add this line if you want to avoid checking in source code from the Xcode workspace
76 | # *.xcworkspace
77 |
78 | # Carthage
79 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
80 | # Carthage/Checkouts
81 |
82 | Carthage/Build/
83 |
84 | # fastlane
85 | # It is recommended to not store the screenshots in the git repo.
86 | # Instead, use fastlane to re-generate the screenshots whenever they are needed.
87 | # For more information about the recommended setup visit:
88 | # https://docs.fastlane.tools/best-practices/source-control/#source-control
89 |
90 | fastlane/report.xml
91 | fastlane/Preview.html
92 | fastlane/screenshots/**/*.png
93 | fastlane/test_output
94 |
95 | # Code Injection
96 | # After new code Injection tools there's a generated folder /iOSInjectionProject
97 | # https://github.com/johnno1962/injectionforxcode
98 |
99 | iOSInjectionProject/
100 |
101 | ### Objective-C Patch ###
102 |
103 | ### Swift ###
104 | # Xcode
105 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
106 |
107 |
108 |
109 |
110 |
111 |
112 | ## Playgrounds
113 | timeline.xctimeline
114 | playground.xcworkspace
115 |
116 | # Swift Package Manager
117 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
118 | # Packages/
119 | # Package.pins
120 | # Package.resolved
121 | # *.xcodeproj
122 | # Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata
123 | # hence it is not needed unless you have added a package configuration file to your project
124 | # .swiftpm
125 |
126 | .build/
127 |
128 | # CocoaPods
129 | # We recommend against adding the Pods directory to your .gitignore. However
130 | # you should judge for yourself, the pros and cons are mentioned at:
131 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
132 | # Pods/
133 | # Add this line if you want to avoid checking in source code from the Xcode workspace
134 | # *.xcworkspace
135 |
136 | # Carthage
137 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
138 | # Carthage/Checkouts
139 |
140 |
141 | # Accio dependency management
142 | Dependencies/
143 | .accio/
144 |
145 | # fastlane
146 | # It is recommended to not store the screenshots in the git repo.
147 | # Instead, use fastlane to re-generate the screenshots whenever they are needed.
148 | # For more information about the recommended setup visit:
149 | # https://docs.fastlane.tools/best-practices/source-control/#source-control
150 |
151 |
152 | # Code Injection
153 | # After new code Injection tools there's a generated folder /iOSInjectionProject
154 | # https://github.com/johnno1962/injectionforxcode
155 |
156 |
157 | ### SwiftPackageManager ###
158 | Packages
159 | xcuserdata
160 | *.xcodeproj
161 |
162 |
163 | ### SwiftPM ###
164 |
165 |
166 | ### Xcode ###
167 |
168 | ## Xcode 8 and earlier
169 |
170 | ### Xcode Patch ###
171 | *.xcodeproj/*
172 | !*.xcodeproj/project.pbxproj
173 | !*.xcodeproj/xcshareddata/
174 | !*.xcworkspace/contents.xcworkspacedata
175 | /*.gcno
176 | **/xcshareddata/WorkspaceSettings.xcsettings
177 |
178 |
179 | # Bundler
180 | /.bundle
181 | /vendor/bundle
182 |
--------------------------------------------------------------------------------