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

major update #21

Open
wants to merge 107 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
107 commits
Select commit Hold shift + click to select a range
c4bba05
compatibility with xcode beta 5
workingDog Aug 9, 2019
939a758
added disabled dates option
workingDog Aug 25, 2019
5932f84
Added disabled dates
workingDog Aug 25, 2019
ad45bfb
update
workingDog Aug 25, 2019
3819af9
update
workingDog Aug 25, 2019
c7f1dd0
update
workingDog Aug 25, 2019
22c4bf6
update
workingDog Aug 25, 2019
037b27a
minor update
workingDog Aug 25, 2019
028014e
range dates
workingDog Aug 26, 2019
ba9d308
update
workingDog Aug 26, 2019
b27fdaf
update
workingDog Aug 26, 2019
faeceed
update
workingDog Aug 26, 2019
43a724c
update
workingDog Aug 26, 2019
f064674
update
workingDog Aug 26, 2019
88fab7e
update
workingDog Aug 26, 2019
27cd948
single date deselection
workingDog Aug 26, 2019
520d273
minor update
workingDog Aug 26, 2019
dc0aebc
update
workingDog Aug 26, 2019
385ac6f
round selection
workingDog Aug 27, 2019
6fb8ed0
minor update
workingDog Aug 27, 2019
4c723a6
minor update
workingDog Aug 27, 2019
c3f3c93
minor update
workingDog Aug 27, 2019
9e0044e
added horizontal scrolling
workingDog Aug 27, 2019
a79215e
Added horizontal scrolling
workingDog Aug 27, 2019
bf9c5a3
Added horizontal scrolling
workingDog Aug 27, 2019
9855527
minor update
workingDog Aug 27, 2019
2f4a665
minor update
workingDog Aug 27, 2019
4d5ee53
xCode 11 beta 7
workingDog Aug 28, 2019
c254602
added color settings
workingDog Aug 29, 2019
bd18f25
more colors
workingDog Aug 29, 2019
a2939a5
more colors
workingDog Aug 29, 2019
ae72221
more colors
workingDog Aug 29, 2019
5b140a5
color settings
workingDog Aug 29, 2019
2a25631
color settings
workingDog Aug 29, 2019
9ac342c
new update
workingDog Oct 7, 2019
09c5a88
new update
workingDog Oct 7, 2019
663d438
new update
workingDog Oct 7, 2019
321fa91
Merge branch 'master' into master
RaffiKian Oct 21, 2019
7b49221
time on long press
workingDog Oct 24, 2019
5143caf
update
workingDog Oct 24, 2019
9d42e8d
time selection
workingDog Oct 25, 2019
95dc2f0
time selection on long press
workingDog Oct 25, 2019
17e933a
minor update
workingDog Nov 24, 2019
d34edc1
minor update
workingDog Nov 24, 2019
0317b6b
time picker
workingDog Nov 25, 2019
e06c9e1
added disabled setting
workingDog Nov 27, 2019
c17644e
minor update
workingDog Jan 7, 2020
ba22600
minor update
workingDog Jan 7, 2020
bb3a753
horizontal and weekly views
workingDog Jan 9, 2020
a69d1d4
horizontal and weekly view
workingDog Jan 9, 2020
690e762
removed ClockPicker
workingDog Jan 9, 2020
fe8c4e9
added paging
workingDog Jan 11, 2020
4029c31
weekly view paging
workingDog Jan 11, 2020
16cb92f
minor code clean
workingDog Feb 1, 2020
9acba81
very minor cleanup
workingDog Feb 1, 2020
c854de3
re-structure project
workingDog Feb 5, 2020
eda874f
public class and struct
workingDog Feb 5, 2020
092289f
removed RKWeeklyViewController
workingDog Mar 6, 2020
8be025e
removed RKWeeklyViewController
workingDog Mar 6, 2020
f658687
removed RKWeeklyViewController
workingDog Mar 6, 2020
d049104
start on date
workingDog Mar 10, 2020
f532c1f
more speed
workingDog Mar 10, 2020
bb12482
update
workingDog Mar 10, 2020
762c0e5
speed up
workingDog Mar 10, 2020
4770a2b
added locale
workingDog Mar 23, 2020
67d3862
added locale
workingDog Mar 23, 2020
df9c361
update
workingDog Mar 23, 2020
cef85a3
update
workingDog Mar 23, 2020
e77c59f
update
workingDog Mar 23, 2020
a94c0a8
very minor update
workingDog Apr 7, 2020
2bfe663
very minor update
workingDog Apr 7, 2020
aedb635
prep for SPM
workingDog May 29, 2020
870f988
prep for SPM
workingDog May 29, 2020
aaa8c40
prep for SPM
workingDog May 29, 2020
0689591
prep for SPM
workingDog May 29, 2020
bff1600
prep for SPM
workingDog May 29, 2020
5a657e2
prep for SPM
workingDog May 29, 2020
e938a1d
prep for SPM
workingDog May 29, 2020
c41e0ac
prep for SPM
workingDog May 29, 2020
86c69ce
prep for SPM
workingDog May 29, 2020
7634812
prep for SPM
workingDog May 29, 2020
ac5a915
scroll adjustment
workingDog May 29, 2020
ac5dffe
minor update
workingDog May 30, 2020
24da320
added RKHoursMinutesPicker
workingDog May 30, 2020
7055eb9
minor fix
workingDog Aug 17, 2020
82d6a4c
migrate to ios14
workingDog Aug 19, 2020
0cea8dd
minor update
workingDog Aug 21, 2020
8637540
minor update
workingDog Aug 21, 2020
68fc8be
code clean
workingDog Aug 21, 2020
9b3810f
make rkManager EnvironmentObject
workingDog Aug 21, 2020
7eb6e76
added ios-14 app
workingDog Aug 21, 2020
ff9c92b
minor cleanup
workingDog Aug 22, 2020
0c992a3
added RKSelectionMode
workingDog Sep 3, 2020
0a957aa
minor update
workingDog Oct 5, 2020
e7b7333
package
workingDog Dec 8, 2020
d4169cc
package
workingDog Dec 8, 2020
9a56926
typo
workingDog Dec 8, 2020
b61d3de
added Example file
workingDog Dec 8, 2020
441867d
renaming
workingDog Dec 8, 2020
ca61563
update
workingDog Dec 8, 2020
90b6cf2
update
workingDog Dec 8, 2020
db0cd27
remove xcodeproj
workingDog Dec 8, 2020
64a5a93
minor update
workingDog Dec 8, 2020
c51e67c
minor update
workingDog Dec 9, 2020
086e769
minor updates
workingDog Feb 4, 2023
d8e18cf
minor update
workingDog Feb 4, 2023
2259751
removed AnyView + minor updates
workingDog Feb 7, 2023
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

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,18 @@
<integer>0</integer>
</dict>
</dict>
<key>SuppressBuildableAutocreation</key>
<dict>
<key>RKCalendar</key>
<dict>
<key>primary</key>
<true/>
</dict>
<key>RKCalendarTests</key>
<dict>
<key>primary</key>
<true/>
</dict>
</dict>
</dict>
</plist>
179 changes: 179 additions & 0 deletions Example.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
import SwiftUI
import RKCalendar



enum TestOptions: String {
case singleDate
case dateRange
case multiDate
case disabled
case timeSetting
case weekly
case horizontal
}

extension TestOptions: Identifiable {
var id: RawValue { rawValue }
}

struct ContentView : View {

@State var isPresented: TestOptions?

@StateObject var rkManager1 = RKManager(calendar: Calendar.current, minimumDate: Date().addingTimeInterval(-60*60*24*60), maximumDate: Date().addingTimeInterval(60*60*24*90), mode: .singleDate)

@StateObject var rkManager2 = RKManager(calendar: Calendar.current, minimumDate: Date().addingTimeInterval(-60*60*24*60), maximumDate: Date().addingTimeInterval(60*60*24*90), mode: .dateRange) // automatically goes to mode=2 after start selection, and vice versa.

@StateObject var rkManager3 = RKManager(calendar: Calendar.current, minimumDate: Date().addingTimeInterval(-60*60*24*60), maximumDate: Date().addingTimeInterval(60*60*24*90), mode: .multiDate)

@StateObject var rkManager4 = RKManager(calendar: Calendar.current, minimumDate: Date().addingTimeInterval(-60*60*24*60), maximumDate: Date().addingTimeInterval(60*60*24*90), mode: .singleDate)

@StateObject var rkManager5 = RKManager(calendar: Calendar.current, minimumDate: Date().addingTimeInterval(-60*60*24*60), maximumDate: Date().addingTimeInterval(60*60*24*90), mode: .singleDate)

@StateObject var rkManager6 = RKManager(calendar: Calendar.current, minimumDate: Date().addingTimeInterval(-60*60*24*60), maximumDate: Date().addingTimeInterval(60*60*24*90), mode: .singleDate)

@StateObject var rkManager7 = RKManager(calendar: Calendar.current, minimumDate: Date().addingTimeInterval(-60*60*24*60), maximumDate: Date().addingTimeInterval(60*60*24*90), mode: .singleDate)


var body: some View {
VStack (spacing: 10) {
Group {
Button(action: { isPresented = .singleDate }) {
Text("Example 1 - Single Date Selection").foregroundColor(.blue)
}
Text(getTextFromDate(rkManager1.selectedDate))

Button(action: { isPresented = .dateRange }) {
VStack {
Text("Example 2 - Range of Dates Selection").foregroundColor(.blue)
Text("(end date > start date)").foregroundColor(.blue)
}
}
VStack {
Text(getTextFromDate(rkManager2.startDate))
Text(getTextFromDate(rkManager2.endDate))
}

Button(action: { isPresented = .multiDate }) {
Text("Example 3 - Multiple Dates Selection ").foregroundColor(.blue)
}
datesView(dates: rkManager3.selectedDates)
}
Group {
Button(action: { isPresented = .disabled }) {
Text("Example 4 - Disabled Dates Setting").foregroundColor(.blue)
}
datesView(dates: rkManager4.disabledDates)

Button(action: { isPresented = .timeSetting }) {
Text("Example 5 - Time setting on long press").foregroundColor(.blue)
}
Text(getTextFromDateTime(rkManager5.selectedDate))

Button(action: { isPresented = .weekly }) {
Text("Example 6 - Weekly view").foregroundColor(.blue)
}
Text(getTextFromDate(rkManager6.selectedDate))

Button(action: { isPresented = .horizontal }) {
Text("Example 7 - Horizontal view with paging").foregroundColor(.blue)
}
Text(getTextFromDate(rkManager7.selectedDate))
}
}
.sheet(item: $isPresented) { selection in
switch selection {
case .singleDate: RKCalendarView().environmentObject(rkManager1)
case .dateRange: RKCalendarView().environmentObject(rkManager2)
case .multiDate: RKCalendarView().environmentObject(rkManager3)
case .disabled: RKCalendarView().environmentObject(rkManager4)
case .timeSetting: RKCalendarView().environmentObject(rkManager5)
case .weekly: RKCalendarView().environmentObject(rkManager6)
case .horizontal: RKCalendarView().environmentObject(rkManager7)
}
}
.onAppear(perform: startUp)
.navigationViewStyle(StackNavigationViewStyle())
}

func datesView(dates: [Date], _ withTime: Bool = false) -> some View {
ScrollView (.horizontal) {
HStack {
ForEach(dates, id: \.self) { date in
withTime ? Text(getTextFromDateTime(date)) : Text(getTextFromDate(date))
}
}
}.padding(.horizontal, 5)
}

func startUp() {

// example of horizontal view
// rkManager1.isVertical = false

// example of pre-setting selected dates
let testOnDates = [Date().addingTimeInterval(60*60*24), Date().addingTimeInterval(60*60*24*2)]
rkManager3.selectedDates.append(contentsOf: testOnDates)

// example of some foreground colors
rkManager3.colors.weekdayHeaderColor = Color.blue
rkManager3.colors.monthHeaderColor = Color.green
rkManager3.colors.textColor = Color.blue
rkManager3.colors.disabledColor = Color.red

// example of pre-setting disabled dates
let testOffDates = [
Date().addingTimeInterval(60*60*24*4),
Date().addingTimeInterval(60*60*24*5),
Date().addingTimeInterval(60*60*24*7)]
rkManager4.disabledDates.append(contentsOf: testOffDates)

// example of allowing time (hh:mm) to be set and displayed on a long press
// example to display in Japanese
rkManager5.locale = Locale(identifier: "ja")
rkManager5.displayTime = true

// example of weekly view with "paging"
rkManager6.isVertical = false
rkManager6.isWeeklyView = true
rkManager6.isContinuous = false
rkManager6.colors.weekdayHeaderColor = Color.blue
rkManager6.colors.monthHeaderColor = Color.green

// example of horizontal monthly view with "paging"
rkManager7.isVertical = false
rkManager7.isContinuous = false
rkManager7.colors.weekdayHeaderColor = Color.blue
rkManager7.colors.monthHeaderColor = Color.green
}

func getDateTimeAsString(_ date: Date?) -> String {
if date == nil { return "" }
let format = DateFormatter()
format.dateFormat = "yyyy-MM-dd-HH-mm"
format.timeZone = TimeZone.current
format.locale = Locale.current
return format.string(from: date!)
}

func getTextFromDate(_ date: Date?) -> String {
if date == nil { return "" }
let formatter = DateFormatter()
formatter.timeZone = TimeZone.current
formatter.locale = Locale.current
formatter.dateFormat = "EEEE, MMMM d, yyyy"
return formatter.string(from: date!)
}

func getTextFromDateTime(_ date: Date?) -> String {
if date == nil { return "" }
let formatter = DateFormatter()
formatter.timeZone = TimeZone.current
formatter.locale = Locale.current
formatter.dateFormat = "EEEE, MMMM d HH:mm, yyyy"
return formatter.string(from: date!)
}

}

29 changes: 29 additions & 0 deletions Package.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// 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: "RKCalendar",
platforms: [.iOS(.v16), .macOS(.v13)],
products: [
// Products define the executables and libraries a package produces, and make them visible to other packages.
.library(
name: "RKCalendar",
targets: ["RKCalendar"]),
],
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: "RKCalendar",
dependencies: []),
.testTarget(
name: "RKCalendarTests",
dependencies: ["RKCalendar"]),
]
)
135 changes: 110 additions & 25 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,51 +1,136 @@
# RKCalendar
SwiftUI Simple Calendar / Date Picker for iOS

**RKCalendar** is a SwiftUI Calendar / Date Picker for iOS and MacOS.


### Features include:

- minimum and maximum calendar dates selectable,
- single date selection,
- range of dates selection,
- multi-dates selection,
- disabled dates setting,
- time selection,
- horizontal view,
- weekly view.


### Light Mode
<img src="https://github.com/RaffiKian/RKCalendar/blob/master/RKCalendar/Images/demo-app-light-mode-1.png" alt="demo app first screenshot" width="260"/> <img src="https://github.com/RaffiKian/RKCalendar/blob/master/RKCalendar/Images/demo-app-light-mode-2.png" alt="demo app first screenshot" width="260"/>
### Dark Mode
<img src="https://github.com/RaffiKian/RKCalendar/blob/master/RKCalendar/Images/demo-app-dark-mode-1.png" alt="demo app first screenshot" width="260"/> <img src="https://github.com/RaffiKian/RKCalendar/blob/master/RKCalendar/Images/demo-app-dark-mode-2.png" alt="demo app first screenshot" width="260"/>

**⚠️ WARNING ⚠️** This is an early version of this library that requires Swift 5.1 and Xcode 11 that are currently still in beta.

# Requirements
- iOS 13.0+
- Xcode 11+
- Swift 5.1+

- iOS 14+, MacOS 11+
- Swift 5.3+

# Installation
You can integrate RKCalendar into your project manually.

To install this version of `RKCalendar` via the official [Swift Package Manager](https://swift.org/package-manager/).

Select `Xcode`>`File`> `Add Packages` and use `https://github.com/workingDog/RKCalendar`


# Usage

//Provide Calendar, minimum and maximum date that can be selected
Typically create a **RKManager** and pass it to a **RKCalendarView**, for example:

```swift
import SwiftUI
import RKCalendar

struct ContentView : View {

@State var showCalendar = false
@StateObject var rkManager = RKManager(calendar: Calendar.current, minimumDate: Date().addingTimeInterval(-60*60*24*60), maximumDate: Date().addingTimeInterval(60*60*24*90), mode: .singleDate)

var body: some View {
Button(action: { showCalendar.toggle() }) {
Text("Example - Single Date Selection").foregroundColor(.blue)
}
.sheet(isPresented: $showCalendar) {
RKCalendarView().environmentObject(rkManager)
}
}
}
}
```

RKManager(calendar: Calendar.current, minimumDate: Date(), maximumDate: Date().addingTimeInterval(60*60*24*365)
## Calendar minimum and maximum date setting

## Single Date Selection
Setting the calendar, minimum and maximum dates that can be selected.

//Pass mode 0 to select a single date
RKManager(calendar: Calendar.current, minimumDate: Date(), maximumDate: Date().addingTimeInterval(60*60*24*365), mode: .singleDate)

PresentationLink(destination: RKViewController(rkManager : self.exampleOne, mode: 0), label:{
Text(getTextFromDate(date: self.exampleOne.selectedDate, mode: 0))
}
)
## Single date selection

## Start and End Date Selection
Use mode *.singleDate* to select a single date.

//Pass mode 1 to select start date
RKManager(calendar: Calendar.current, minimumDate: Date(), maximumDate: maxDate, mode: .singleDate)

PresentationLink(destination: RKViewController(rkManager : self.exampleTwo, mode: 1), label:{
Text(getTextFromDate(date: self.exampleTwo.startDate, mode: 1))
}
)
## Range of dates selection

Use mode *.dateRange* to select a contiguous range of dates, from a start date to an end date.

RKManager(calendar: Calendar.current, minimumDate: Date(), maximumDate: maxDate, mode: .dateRange)

Note, mode *.dateRange* is automatically toggled internally and the end date must be greater than the start date.

## Multi-dates selection

Use mode *.multiDate* for selecting a number of dates.

RKManager(calendar: Calendar.current, minimumDate: Date(), maximumDate: maxDate, mode: .multiDate)

## Disabled-dates setting

Use any mode and set zero or more dates to be disabled (un-selectable).

For example:

var rkManager = RKManager(calendar: Calendar.current, minimumDate: Date(), maximumDate: maxDate, mode: .singleDate)

rkManager.disabledDates.append(contentsOf: [
Date().addingTimeInterval(60*60*24*4),
Date().addingTimeInterval(60*60*24*5),
Date().addingTimeInterval(60*60*24*7)
])

## Time selection

**RKTimeView** allows for a time (hh:mm) selection option on a long press.

Time selection is activated by setting **displayTime=true** in RKManager (default **false**).
On a long press, a time selection view will popup allowing hours and minutes to be selected.
Time selection is available for all modes. For mode ".dateRange", select the start and end dates as usual with a tap, then with a long press, select the time desired.

## Horizontal view

An **horizontal view** of the calendar is activated by setting **isVertical=false** in RKManager (default **true**).


## Weekly view

An **weekly view** of the calendar is activated by setting **isWeeklyView=true** in RKManager (default **false**). Note you must also set **isVertical=false**. Currently only works with **isContinuous=false**, that is, horizontal paging only.


## Language

The language of the calendar is activated by setting **locale** in RKManager (default **Local.curent**) to display the months and weeks in the chosen language.


## Other options

The RKCalendar can be in two scrolling modes, a continuous mode to display a scrolling calendar of months, or a one month at a time (paging) scrolling view. This is activated by setting **isContinuous** in RKManager (default **true**).

RKCalendar can prevent a user input for the current mode by setting **disabled=true** in RKManager (default **false**).

Various elements of **RKCalendar**, such as the monthly headings, can be colored. This is achieved by customising the relevent **RKManager.colors**.

//Pass mode 2 to select end date

PresentationLink(destination: RKViewController(rkManager : self.exampleTwo, mode: 2), label:{
Text(getTextFromDate(date: self.exampleTwo.endDate, mode: 2))
}
)

# License

RKCalendar is available under the MIT license. See the LICENSE file for more info.
Loading