Skip to content

Commit

Permalink
Merge pull request #1 from mohamed-arradi/version/v1.0.0
Browse files Browse the repository at this point in the history
IMSwitch 1.0.0
  • Loading branch information
mohamed-arradi authored Nov 26, 2023
2 parents b258454 + a954bf2 commit 87a5458
Show file tree
Hide file tree
Showing 8 changed files with 448 additions and 1 deletion.
8 changes: 8 additions & 0 deletions IMSwitch/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.DS_Store
/.build
/Packages
xcuserdata/
DerivedData/
.swiftpm/configuration/registries.json
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
.netrc
92 changes: 92 additions & 0 deletions IMSwitch/.swiftpm/xcode/xcshareddata/xcschemes/IMSwitch.xcscheme
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1500"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "IMSwitch"
BuildableName = "IMSwitch"
BlueprintName = "IMSwitch"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "NO"
buildForArchiving = "NO"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "IMSwitchTests"
BuildableName = "IMSwitchTests"
BlueprintName = "IMSwitchTests"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "IMSwitchTests"
BuildableName = "IMSwitchTests"
BlueprintName = "IMSwitchTests"
ReferencedContainer = "container:">
</BuildableReference>
</TestableReference>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "IMSwitch"
BuildableName = "IMSwitch"
BlueprintName = "IMSwitch"
ReferencedContainer = "container:">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
21 changes: 21 additions & 0 deletions IMSwitch/Package.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// swift-tools-version: 5.9
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
name: "IMSwitch",
platforms: [.iOS(.v15), .macOS(.v12)],
products: [
.library(
name: "IMSwitch",
targets: ["IMSwitch"]),
],
targets: [
.target(
name: "IMSwitch"),
.testTarget(
name: "IMSwitchTests",
dependencies: ["IMSwitch"]),
]
)
224 changes: 224 additions & 0 deletions IMSwitch/Sources/MyLibrary/IMSwitch.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,224 @@
import SwiftUI
import Foundation

class ToggleState: ObservableObject {
@Published var isPrimaryOptionSelected: Bool = false
@Published var isRTL: Bool = false
}

struct IMSwitch: View {
@StateObject var toggleState: ToggleState
@Environment(\.layoutDirection) var direction

private (set) var leftImage: Image
private (set) var rightImage: Image
private (set) var backgroundColor: Color
private (set) var circleFilledColor: Color
private (set) var animationType: Animation
private (set) var animationLength: Double
private (set) var activeColor: Color

init(leftImage: Image,
rightImage: Image,
activeColor: Color,
circleFilledColor: Color,
backgroundColor: Color,
animation: Animation = .default,
animationLength: Double = 0.35,
toggleState: ToggleState) {
self.circleFilledColor = circleFilledColor
self.leftImage = leftImage
self.rightImage = rightImage
self.activeColor = activeColor
self.backgroundColor = backgroundColor
self.animationType = animation
self.animationLength = animationLength
self._toggleState = .init(wrappedValue: toggleState)
}

var body: some View {
GeometryReader { geometry in
HStack {
if !toggleState.isPrimaryOptionSelected {
Spacer()
}

Circle()
.fill(circleFilledColor)
.frame(width: geometry.size.width / 2,
height: geometry.size.height)
.simultaneousGesture(
DragGesture()
.onEnded { value in
if value.translation.width < 0 {
self.toggleState.isPrimaryOptionSelected = true
} else {
self.toggleState.isPrimaryOptionSelected = false
}
}
)
.onTapGesture {
self.toggleState.isPrimaryOptionSelected.toggle()
}

if toggleState.isPrimaryOptionSelected {
Spacer()
}
}

.overlay(content: {
HStack {
leftImage
.resizable()
.scaledToFit()
.frame(width: geometry.size.width / 4, height: geometry.size.height / 2)
.foregroundColor(toggleState.isPrimaryOptionSelected ? activeColor : circleFilledColor)
.onTapGesture {
if !toggleState.isPrimaryOptionSelected {
self.toggleState.isPrimaryOptionSelected.toggle()
}
}
.simultaneousGesture(
DragGesture()
.onEnded { value in
if value.translation.width < 0 {
self.toggleState.isPrimaryOptionSelected = !toggleState.isRTL
} else {
self.toggleState.isPrimaryOptionSelected = toggleState.isRTL
}
}
)
Spacer()
rightImage
.resizable()
.scaledToFit()
.frame(width: geometry.size.width / 4, height: geometry.size.height / 2)
.foregroundColor(toggleState.isPrimaryOptionSelected ? circleFilledColor : activeColor)
.onTapGesture {
if toggleState.isPrimaryOptionSelected {
self.toggleState.isPrimaryOptionSelected.toggle()
}
}
.simultaneousGesture(
DragGesture()
.onEnded { value in
if value.translation.width < 0 {
self.toggleState.isPrimaryOptionSelected = true
} else {
self.toggleState.isPrimaryOptionSelected = false
}
}
)
}
.padding(EdgeInsets(top: geometry.size.height / 4,
leading: geometry.size.width / 8,
bottom: geometry.size.height / 4,
trailing: geometry.size.width / 8))
})
.frame(width: geometry.size.width, height: geometry.size.height)
.padding(EdgeInsets(top: 20, leading: 10, bottom: 20, trailing: 10))
.background(backgroundColor)
.animation(animationType, value: animationLength)
.cornerRadius(geometry.size.height / 1.6)
}
.shadow(radius: 8)
.onAppear {
toggleState.isRTL = direction == .rightToLeft
}
}
}

#if DEBUG
struct IMSwitch_Previews: PreviewProvider {
static var previews: some View {
Group {
Group {
VStack(spacing: 50) {
IMSwitch(
leftImage: .init(systemName: "bicycle"),
rightImage: .init(systemName: "parkingsign.circle"),
activeColor: .white,
circleFilledColor: .yellow,
backgroundColor: Color.white.opacity(0.85), animation: .easeInOut,
animationLength: 0.35, toggleState: .init())
.frame(width: 200, height: 60)
.environment(\.layoutDirection, .leftToRight)

IMSwitch(
leftImage: .init(systemName: "car"),
rightImage: .init(systemName: "parkingsign.circle"),
activeColor: .white,
circleFilledColor: .blue,
backgroundColor: Color.white.opacity(0.85), animation: .easeInOut,
animationLength: 0.35, toggleState: .init())
.frame(width: 200, height: 60)
.environment(\.layoutDirection, .leftToRight)

IMSwitch(
leftImage: .init(systemName: "bus"),
rightImage: .init(systemName: "train.side.front.car"),
activeColor: .white,
circleFilledColor: .green,
backgroundColor: Color.white.opacity(0.85), animation: .easeInOut,
animationLength: 0.35, toggleState: .init())
.frame(width: 200, height: 60)
.environment(\.layoutDirection, .leftToRight)

IMSwitch(
leftImage: .init(systemName: "person.3"),
rightImage: .init(systemName: "person"),
activeColor: .white,
circleFilledColor: .red,
backgroundColor: Color.white.opacity(0.85), animation: .easeInOut,
animationLength: 0.35, toggleState: .init())
.frame(width: 200, height: 60)
.environment(\.layoutDirection, .leftToRight)
}
}.previewDisplayName("Default preview 1")
}
Group {
VStack(spacing: 50) {
IMSwitch(
leftImage: .init(systemName: "bicycle"),
rightImage: .init(systemName: "parkingsign.circle"),
activeColor: .white,
circleFilledColor: .yellow,
backgroundColor: Color.white.opacity(0.85), animation: .easeInOut,
animationLength: 0.35, toggleState: .init())
.frame(width: 200, height: 60)
.environment(\.layoutDirection, .leftToRight)

IMSwitch(
leftImage: .init(systemName: "car"),
rightImage: .init(systemName: "parkingsign.circle"),
activeColor: .white,
circleFilledColor: .blue,
backgroundColor: Color.white.opacity(0.85), animation: .easeInOut,
animationLength: 0.35, toggleState: .init())
.frame(width: 200, height: 60)
.environment(\.layoutDirection, .leftToRight)

IMSwitch(
leftImage: .init(systemName: "bus"),
rightImage: .init(systemName: "train.side.front.car"),
activeColor: .white,
circleFilledColor: .green,
backgroundColor: Color.white.opacity(0.85), animation: .easeInOut,
animationLength: 0.35, toggleState: .init())
.frame(width: 200, height: 60)
.environment(\.layoutDirection, .leftToRight)

IMSwitch(
leftImage: .init(systemName: "person.3"),
rightImage: .init(systemName: "person"),
activeColor: .white,
circleFilledColor: .red,
backgroundColor: Color.white.opacity(0.85), animation: .easeInOut,
animationLength: 0.35, toggleState: .init())
.frame(width: 200, height: 60)
.environment(\.layoutDirection, .leftToRight)
}
}.previewDisplayName("Default preview 1")
}
}
#endif
4 changes: 4 additions & 0 deletions IMSwitch/Tests/IMSwitchTests/IMSwitchTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import XCTest
@testable import IMSwitch

final class MyLibraryTests: XCTestCase {}
Loading

0 comments on commit 87a5458

Please sign in to comment.