Skip to content

Commit

Permalink
SwiftUI Support (#54)
Browse files Browse the repository at this point in the history
* fix #48 FastisView for presentation in SwiftUI

---------

Co-authored-by: Ilya Kharlamov <[email protected]>
  • Loading branch information
UriyDevyataev and ilia3546 authored Mar 15, 2024
1 parent d8b884d commit 5e45d47
Show file tree
Hide file tree
Showing 7 changed files with 463 additions and 22 deletions.
10 changes: 9 additions & 1 deletion Example/FastisExample.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@
archiveVersion = 1;
classes = {
};
objectVersion = 52;
objectVersion = 54;
objects = {

/* Begin PBXBuildFile section */
1A3E7A5E2A40901600434229 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 1A3E7A602A40901600434229 /* Localizable.strings */; };
1AB955832BA31F4200235243 /* HostingController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1AB955822BA31F4200235243 /* HostingController.swift */; };
1AB955852BA31F5500235243 /* MainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1AB955842BA31F5500235243 /* MainView.swift */; };
F381AF9628B8C7190046383A /* Fastis in Frameworks */ = {isa = PBXBuildFile; productRef = F381AF9528B8C7190046383A /* Fastis */; };
F3FCEE47244780FE000F966E /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3FCEE46244780FE000F966E /* AppDelegate.swift */; };
F3FCEE4B244780FE000F966E /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3FCEE4A244780FE000F966E /* ViewController.swift */; };
Expand All @@ -19,6 +21,8 @@
1A3E7A5F2A40901600434229 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
1A3E7A612A40902000434229 /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/Localizable.strings; sourceTree = "<group>"; };
1A3E7A622A409B3A00434229 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Localizable.strings; sourceTree = "<group>"; };
1AB955822BA31F4200235243 /* HostingController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HostingController.swift; sourceTree = "<group>"; };
1AB955842BA31F5500235243 /* MainView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainView.swift; sourceTree = "<group>"; };
CB137E4877EBDC6E87A77A4B /* Pods_FastisExample.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_FastisExample.framework; sourceTree = BUILT_PRODUCTS_DIR; };
F31CFB6B28B8C32D00364F6A /* Fastis */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = Fastis; path = ..; sourceTree = "<group>"; };
F3FCEE43244780FE000F966E /* FastisExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = FastisExample.app; sourceTree = BUILT_PRODUCTS_DIR; };
Expand Down Expand Up @@ -80,6 +84,8 @@
children = (
F3FCEE46244780FE000F966E /* AppDelegate.swift */,
F3FCEE4A244780FE000F966E /* ViewController.swift */,
1AB955822BA31F4200235243 /* HostingController.swift */,
1AB955842BA31F5500235243 /* MainView.swift */,
F3FCEE4F24478100000F966E /* Assets.xcassets */,
F3FCEE5124478100000F966E /* LaunchScreen.storyboard */,
F3FCEE5424478100000F966E /* Info.plist */,
Expand Down Expand Up @@ -164,6 +170,8 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
1AB955832BA31F4200235243 /* HostingController.swift in Sources */,
1AB955852BA31F5500235243 /* MainView.swift in Sources */,
F3FCEE4B244780FE000F966E /* ViewController.swift in Sources */,
F3FCEE47244780FE000F966E /* AppDelegate.swift in Sources */,
);
Expand Down
26 changes: 26 additions & 0 deletions Example/Source/HostingController.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//
// HostingController.swift
// FastisExample
//
// Created by Yriy Devyataev on 13.03.2024.
// Copyright © 2024 RetailDriver LLC. All rights reserved.
//

import SwiftUI

/**
The view is used to display SwiftUI view in the UIKit project
*/

class HostingController: UIHostingController<MainView> {

init() {
super.init(rootView: MainView())
}

@available(*, unavailable)
dynamic required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

}
91 changes: 91 additions & 0 deletions Example/Source/MainView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
//
// CalendarView.swift
// FastisExample
//
// Created by Yriy Devyataev on 13.03.2024.
// Copyright © 2024 RetailDriver LLC. All rights reserved.
//

import Fastis
import Foundation
import SwiftUI
import UIKit

/**
View is used as a possible example of a SwiftUI project.
*/
struct MainView: View {

private let calendar: Calendar = .current

@State private var showSingleCalendar = false
@State private var showRangeCalendar = false
@State private var currentValueText = "Choose a date"

@State var currentValue: FastisValue? {
didSet {
if let rangeValue = self.currentValue as? FastisRange {
self.currentValueText = self.dateFormatter.string(from: rangeValue.fromDate) + " - " + self.dateFormatter
.string(from: rangeValue.toDate)
} else if let date = self.currentValue as? Date {
self.currentValueText = self.dateFormatter.string(from: date)
} else {
self.currentValueText = "Choose a date"
}
}
}

private var dateFormatter: DateFormatter {
let formatter = DateFormatter()
formatter.dateFormat = "dd/MM/yyyy"
formatter.calendar = self.calendar
return formatter
}

var body: some View {
VStack(spacing: 32, content: {
Text(self.currentValueText)
VStack(alignment: .center, spacing: 16, content: {
Button("Choose range of dates") {
self.showRangeCalendar.toggle()
}
Button("Choose single date") {
self.showSingleCalendar.toggle()
}
})
})
.navigationTitle("SwiftUI presentation")
.frame(maxWidth: .infinity, maxHeight: .infinity)
.sheet(isPresented: self.$showRangeCalendar) {
FastisView(mode: .range) { action in
if case .done(let newValue) = action {
self.currentValue = newValue
}
}
.title("Choose range")
.initialValue(self.currentValue as? FastisRange)
.minimumDate(self.calendar.date(byAdding: .month, value: -2, to: Date()))
.maximumDate(self.calendar.date(byAdding: .month, value: 3, to: Date()))
.allowToChooseNilDate(true)
.allowDateRangeChanges(false)
.shortcuts([.lastWeek, .lastMonth])
.selectMonthOnHeaderTap(true)
.ignoresSafeArea()
}
.sheet(isPresented: self.$showSingleCalendar) {
FastisView(mode: .single) { action in
if case .done(let newValue) = action {
self.currentValue = newValue
}
}
.title("Choose date")
.initialValue(self.currentValue as? Date)
.minimumDate(self.calendar.date(byAdding: .month, value: -2, to: Date()))
.maximumDate(Date())
.allowToChooseNilDate(true)
.shortcuts([.yesterday, .today, .tomorrow])
.closeOnSelectionImmediately(true)
.ignoresSafeArea()
}
}
}
26 changes: 21 additions & 5 deletions Example/Source/ViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,17 @@ class ViewController: UIViewController {
return button
}()

private lazy var chooseSingleButtonWithCustomCalendar: UIButton = {
private lazy var chooseRangeButtonWithCustomCalendar: UIButton = {
let button = UIButton(type: .system)
button.setTitle("Choose single date with custom calendar", for: .normal)
button.addTarget(self, action: #selector(self.chooseSingleDateWithCustomCalendar), for: .touchUpInside)
button.setTitle("Choose range of dates with custom calendar", for: .normal)
button.addTarget(self, action: #selector(self.chooseRangeWithCustomCalendar), for: .touchUpInside)
return button
}()

private lazy var chooseWithSwiftUI: UIButton = {
let button = UIButton(type: .system)
button.setTitle("Choose with SwiftUI", for: .normal)
button.addTarget(self, action: #selector(self.swiftUIPresentation), for: .touchUpInside)
return button
}()

Expand Down Expand Up @@ -91,7 +98,8 @@ class ViewController: UIViewController {
self.containerView.setCustomSpacing(32, after: self.currentDateLabel)
self.containerView.addArrangedSubview(self.chooseRangeButton)
self.containerView.addArrangedSubview(self.chooseSingleButton)
self.containerView.addArrangedSubview(self.chooseSingleButtonWithCustomCalendar)
self.containerView.addArrangedSubview(self.chooseRangeButtonWithCustomCalendar)
self.containerView.addArrangedSubview(self.chooseWithSwiftUI)
self.view.addSubview(self.containerView)
}

Expand Down Expand Up @@ -149,7 +157,7 @@ class ViewController: UIViewController {
}

@objc
private func chooseSingleDateWithCustomCalendar() {
private func chooseRangeWithCustomCalendar() {
var customConfig: FastisConfig = .default
var calendar: Calendar = .init(identifier: .islamicUmmAlQura)
calendar.locale = .autoupdatingCurrent
Expand All @@ -175,4 +183,12 @@ class ViewController: UIViewController {
fastisController.present(above: self)
}

@objc
private func swiftUIPresentation() {
let hostingController = HostingController()
hostingController.modalPresentationStyle = .custom
let navVC = self.parent as? UINavigationController
navVC?.pushViewController(hostingController, animated: true)
}

}
51 changes: 49 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ Fastis is a fully customisable UI component for picking dates and ranges created
- [Configuration](#configuration)
- [Shortcuts](#shortcuts)
- [Customization](#customization)
- [SwiftUI](#swiftui)
- [Credits](#credits)
- [License](#license)

Expand Down Expand Up @@ -161,7 +162,6 @@ var maximumDate: Date? = nil
var selectMonthOnHeaderTap: Bool = true
var allowDateRangeChanges: Bool = true
var closeOnSelectionImmediately: Bool = false

```

- `shortcuts`- Shortcuts array. The default value is `[]`. See [Shortcuts](#shortcuts) section
Expand Down Expand Up @@ -226,7 +226,7 @@ To customise a special FastisController instance with custom calendar:

```swift
var customConfig: FastisConfig = .default
var calendar: Calendar = .init(identifier: .islamicUmmAlQura)
var calendar = Calendar(identifier: .islamicUmmAlQura)
calendar.locale = .autoupdatingCurrent
customConfig.calendar = calendar
let fastisController = FastisController(mode: .range, config: customConfig)
Expand All @@ -246,9 +246,56 @@ config.todayCell.circleViewColor = .red

If you don't want to customzie today date cell, just set `config.todayCell = nil` and today cell will use `dayCell` config.

### SwiftUI

The library also contains a SwiftUI wrapper

If you want to get a date range:

```swift
FastisView(mode: .single, dismissHandler: { action in
switch action {
case .done(let resultDate):
print(resultDate) // resultDate is Date
case .cancel:
...
}
})
.title("Choose range")
.initialValue(self.currentValue as? FastisRange)
.minimumDate(Calendar.current.date(byAdding: .month, value: -2, to: Date()))
.maximumDate(Calendar.current.date(byAdding: .month, value: 3, to: Date()))
.allowToChooseNilDate(true)
.allowDateRangeChanges(false)
.shortcuts([.lastWeek, .lastMonth])
.selectMonthOnHeaderTap(true)
```

If you want to get a single date:

```swift
FastisView(mode: .range, dismissHandler: { action in
switch action {
case .done(let resultRange):
print(resultRange) // resultRange is FastisRange
case .cancel:
...
}
})
.title("Choose date")
.initialValue(self.currentValue as? Date)
.minimumDate(Calendar.current.date(byAdding: .month, value: -2, to: Date()))
.maximumDate(Date())
.allowToChooseNilDate(true)
.allowDateRangeChanges(false)
.shortcuts([.yesterday, .today, .tomorrow])
.closeOnSelectionImmediately(true)
```

## Credits

- Ilya Kharlamov ([@ilia3546](https://github.com/ilia3546))
- Uriy Devyataev ([@UriyDevyataev](https://github.com/UriyDevyataev))

## License

Expand Down
Loading

0 comments on commit 5e45d47

Please sign in to comment.