Skip to content

Commit

Permalink
CAL-46: Create code documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
FulcrumOne authored Dec 3, 2023
1 parent b227c1e commit 37974bb
Show file tree
Hide file tree
Showing 8 changed files with 120 additions and 64 deletions.
23 changes: 23 additions & 0 deletions Sources/Internal/Enums/MWeekday.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//
// MWeekday.swift of CalendarView
//
// Created by Alina Petrovska on 29.10.2023.
// - Mail: alina.petrovskaya@mijick.com
// - GitHub: https://github.com/Mijick
//
// Copyright ©2023 Mijick. Licensed under MIT License.


extension MWeekday {
static var allCases: [MWeekday] {
let firstDayIndex = MCalendar.firstWeekday.rawValue
let weekDaysIndexes = [Int](firstDayIndex ... 7) + [Int](1 ..< firstDayIndex)

return .init(weekDaysIndexes)
}
}

// MARK: - Helpers
fileprivate extension [MWeekday] {
init(_ indexes: [Int]) { self = indexes.compactMap { .init(rawValue: $0) }}
}
45 changes: 38 additions & 7 deletions Sources/Public/Configurables/Public+CalendarConfig.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,37 +13,68 @@ import SwiftUI

// MARK: - Calendar Configuration
public extension CalendarConfig {
/// Sets the start date of the calendar.
/// DEFAULT: Current month
func startMonth(_ value: Date) -> Self { MCalendar.startDate = value.start(of: .month); return self }

/// Sets the end date of the calendar.
/// DEFAULT: A date in 10 years
func endMonth(_ value: Date) -> Self { MCalendar.endDate = value.end(of: .month); return self }

/// Sets the first day of the week.
/// DEFAULT:: Monday
func firstWeekday(_ value: MWeekday) -> Self { MCalendar.firstWeekday = value; return self }

/// Sets the locale of the calendar.
/// DEFAULT: AutoupdatingCurrent
func locale(_ value: Locale) -> Self { MCalendar.locale = value; return self }
}

// MARK: - Distances Between Objects
public extension CalendarConfig {
/// Sets the top scroll padding in the view.
func monthsTopPadding(_ value: CGFloat) -> Self { changing(path: \.monthsPadding.top, to: value) }

/// Sets the bottom scroll padding in the view.
func monthsBottomPadding(_ value: CGFloat) -> Self { changing(path: \.monthsPadding.bottom, to: value) }

/// Sets the distance between the month label and the day cell in the view.
func monthLabelToDaysDistance(_ value: CGFloat) -> Self { changing(path: \.monthLabelDaysSpacing, to: value) }

/// Sets the spacing between months in the view.
func monthsSpacing(_ value: CGFloat) -> Self { changing(path: \.monthsSpacing, to: value) }

/// Sets the vertical spacing between day cells in the view.
func daysVerticalSpacing(_ value: CGFloat) -> Self { changing(path: \.daysSpacing.vertical, to: value) }

/// Sets the horizontal spacing between day cells in the view.
func daysHorizontalSpacing(_ value: CGFloat) -> Self { changing(path: \.daysSpacing.horizontal, to: value) }
}

// MARK: - Custom Views
// MARK: - View Customisation
public extension CalendarConfig {
func monthLabel(_ builder: @escaping (Date) -> some MonthLabel) -> Self { changing(path: \.monthLabel, to: builder) }
func weekdaysView(_ builder: @escaping () -> some WeekdaysView) -> Self { changing(path: \.weekdaysView, to: builder) }
func dayView(_ builder: @escaping (Date, Bool, Binding<Date?>?, Binding<MDateRange?>?) -> some DayView) -> Self { changing(path: \.dayView, to: builder) }
/// Sets the background for the months view.
func monthsViewBackground(_ value: Color) -> Self { changing(path: \.monthsViewBackground, to: value) }
}

// MARK: - View Customisation
// MARK: - Custom Views
public extension CalendarConfig {
func monthsViewBackground(_ value: Color) -> Self { changing(path: \.monthsViewBackground, to: value) }
/// Replaces the default weekdays view with a selected implementation.
func weekdaysView(_ builder: @escaping () -> some WeekdaysView) -> Self { changing(path: \.weekdaysView, to: builder) }

/// Replaces the default month label with a selected implementation.
func monthLabel(_ builder: @escaping (Date) -> some MonthLabel) -> Self { changing(path: \.monthLabel, to: builder) }

/// Replaces the default day view with a selected implementation.
func dayView(_ builder: @escaping (Date, Bool, Binding<Date?>?, Binding<MDateRange?>?) -> some DayView) -> Self { changing(path: \.dayView, to: builder) }
}

// MARK: - Modifiers
public extension CalendarConfig {
/// Scrolls the calendar to the selected date.
func scrollTo(date: Date?) -> Self { changing(path: \.scrollDate, to: date) }

/// Triggers when a new month is about to be visible.
func onMonthChange(_ value: @escaping (Date) -> ()) -> Self { changing(path: \.onMonthChange, to: value) }
}

Expand All @@ -57,8 +88,8 @@ public struct CalendarConfig: Configurable { public init() {}

private(set) var monthsViewBackground: Color = .clear

private(set) var monthLabel: (Date) -> any MonthLabel = DefaultMonthLabel.init
private(set) var weekdaysView: () -> any WeekdaysView = DefaultWeekdaysView.init
private(set) var monthLabel: (Date) -> any MonthLabel = DefaultMonthLabel.init
private(set) var dayView: (Date, Bool, Binding<Date?>?, Binding<MDateRange?>?) -> any DayView = DefaultDayView.init

private(set) var scrollDate: Date? = nil
Expand Down
15 changes: 0 additions & 15 deletions Sources/Public/Enums/Public+MWeekday.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,4 @@
// Copyright ©2023 Mijick. Licensed under MIT License.


import Foundation

public enum MWeekday: Int { case sunday = 1, monday, tuesday, wednesday, thursday, friday, saturday }
extension MWeekday {
static var allCases: [MWeekday] {
let firstDayIndex = MCalendar.firstWeekday.rawValue
let weekDaysIndexes = [Int](firstDayIndex ... 7) + [Int](1 ..< firstDayIndex)

return .init(weekDaysIndexes)
}
}

// MARK: - Helpers
fileprivate extension [MWeekday] {
init(_ indexes: [Int]) { self = indexes.compactMap { .init(rawValue: $0) }}
}
4 changes: 1 addition & 3 deletions Sources/Public/Extensions/Public+MCalendarView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,5 @@
import SwiftUI

extension MCalendarView {
public init(selectedDate: Binding<Date?>?, selectedRange: Binding<MDateRange?>?, configBuilder: (CalendarConfig) -> CalendarConfig = { $0 }) {
self.init(selectedDate, selectedRange, configBuilder)
}
public init(selectedDate: Binding<Date?>?, selectedRange: Binding<MDateRange?>?, configBuilder: (CalendarConfig) -> CalendarConfig = { $0 }) { self.init(selectedDate, selectedRange, configBuilder) }
}
51 changes: 27 additions & 24 deletions Sources/Public/View Protocols/Public+DayView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,22 +29,14 @@ public protocol DayView: View {
func onSelection()
}

// MARK: - Customising View
// MARK: - Default View Implementation
public extension DayView {
func createContent() -> AnyView { createDefaultContent().erased() }
func createDayLabel() -> AnyView { createDefaultDayLabel().erased() }
func createSelectionView() -> AnyView { createDefaultSelectionView().erased() }
func createRangeSelectionView() -> AnyView { createDefaultRangeSelectionView().erased() }

var body: some View { createBody() }
}
private extension DayView {
func createBody() -> some View {
Group {
if isCurrentMonth { createBodyForCurrentMonth() }
else { createBodyForOtherMonth() }
}
}
func createDefaultContent() -> some View { ZStack {
createSelectionView()
createRangeSelectionView()
Expand All @@ -68,16 +60,6 @@ private extension DayView {
.active(if: isWithinRange())
}
}
private extension DayView {
func createBodyForCurrentMonth() -> some View {
createContent()
.frame(maxWidth: .infinity, maxHeight: .infinity)
.aspectRatio(1.0, contentMode: .fit)
.onAppear(perform: onAppear)
.onTapGesture(perform: onSelection)
}
func createBodyForOtherMonth() -> some View { Rectangle().fill(Color.clear) }
}
private extension DayView {
var rangeSelectionViewCorners: RoundedRectangle.Corner {
if isBeginningOfRange() { return [.topLeft, .bottomLeft] }
Expand All @@ -87,31 +69,52 @@ private extension DayView {
}
}

// MARK: - Handling Actions
// MARK: - Default Logic Implementation
public extension DayView {
func onAppear() {}
func onSelection() { selectedDate?.wrappedValue = date }
}

// MARK: - Text Formatting
// MARK: - Helpers

// MARK: Text Formatting
public extension DayView {
/// Returns a string of the selected format for the date.
func getStringFromDay(format: String) -> String { MDateFormatter.getString(from: date, format: format) }
}

// MARK: - Date Helpers
// MARK: Date Helpers
public extension DayView {
func isPast() -> Bool { date.isBefore(.day, than: .now) }
func isToday() -> Bool { date.isSame(.day, as: .now) }
}

// MARK: - Day Selection Helpers
// MARK: Day Selection Helpers
public extension DayView {
func isSelected() -> Bool { date.isSame(.day, as: selectedDate?.wrappedValue) || isBeginningOfRange() || isEndOfRange() }
}

// MARK: - Range Selection Helpers
// MARK: Range Selection Helpers
public extension DayView {
func isBeginningOfRange() -> Bool { date.isSame(.day, as: selectedRange?.wrappedValue?.getRange()?.lowerBound) }
func isEndOfRange() -> Bool { date.isSame(.day, as: selectedRange?.wrappedValue?.getRange()?.upperBound) }
func isWithinRange() -> Bool { selectedRange?.wrappedValue?.isRangeCompleted() == true && selectedRange?.wrappedValue?.contains(date) == true }
}

// MARK: - Others
public extension DayView {
var body: some View { Group {
if isCurrentMonth { createBodyForCurrentMonth() }
else { createBodyForOtherMonth() }
}}
}
private extension DayView {
func createBodyForCurrentMonth() -> some View {
createContent()
.frame(maxWidth: .infinity, maxHeight: .infinity)
.aspectRatio(1.0, contentMode: .fit)
.onAppear(perform: onAppear)
.onTapGesture(perform: onSelection)
}
func createBodyForOtherMonth() -> some View { Rectangle().fill(Color.clear) }
}
11 changes: 9 additions & 2 deletions Sources/Public/View Protocols/Public+MonthLabel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,16 @@
import SwiftUI

public protocol MonthLabel: View {
// MARK: Required Attributes
var month: Date { get }

// MARK: View Customisation
func createContent() -> AnyView
}

// MARK: - Customizing View
// MARK: - Default View Implementation
public extension MonthLabel {
func createContent() -> AnyView { createDefaultContent().erased() }
var body: some View { createContent() }
}
private extension MonthLabel {
func createDefaultContent() -> some View {
Expand All @@ -31,5 +32,11 @@ private extension MonthLabel {

// MARK: - Helpers
public extension MonthLabel {
/// Returns a string of the selected format for the month.
func getString(format: String) -> String { MDateFormatter.getString(from: month, format: format) }
}

// MARK: - Others
public extension MonthLabel {
var body: some View { createContent() }
}
13 changes: 10 additions & 3 deletions Sources/Public/View Protocols/Public+WeekdayLabel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,16 @@
import SwiftUI

public protocol WeekdayLabel: View {
// MARK: Required Attributes
var weekday: MWeekday { get }

// MARK: View Customisation
func createContent() -> AnyView
}

// MARK: - Customising View
// MARK: - Default View Implementation
public extension WeekdayLabel {
func createContent() -> AnyView { createDefaultContent().erased() }
var body: some View { createContent() }
}
private extension WeekdayLabel {
func createDefaultContent() -> some View {
Expand All @@ -31,8 +32,14 @@ private extension WeekdayLabel {

// MARK: - Helpers
public extension WeekdayLabel {
/// Returns a string of the selected format for the weekday.
func getString(with format: WeekdaySymbolFormat) -> String { MDateFormatter.getString(for: weekday, format: format) }

/// Returns a type-erased object.
func erased() -> AnyWeekdayLabel { .init(self) }
}

// MARK: - Others
public extension WeekdayLabel {
func getString(with format: WeekdaySymbolFormat) -> String { MDateFormatter.getString(for: weekday, format: format) }
var body: some View { createContent() }
}
22 changes: 12 additions & 10 deletions Sources/Public/View Protocols/Public+WeekdaysView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,29 +10,31 @@

import SwiftUI

public protocol WeekdaysView: View {
public protocol WeekdaysView: View {
// MARK: View Customisation
func createContent() -> AnyView
func createWeekdayLabel(_ weekday: MWeekday) -> AnyWeekdayLabel
}

// MARK: - Customising View
// MARK: - Default View Implementation
public extension WeekdaysView {
func createContent() -> AnyView { createDefaultContent().erased() }
func createWeekdaysView() -> AnyView { createDefaultWeekdaysView().erased() }
func createContent() -> AnyView { createWeekdaysView().erased() }
func createWeekdayLabel(_ weekday: MWeekday) -> AnyWeekdayLabel { createDefaultWeekDayLabel(weekday).erased() }

var body: some View { createContent() }
}
private extension WeekdaysView {
func createDefaultContent() -> some View { createWeekdaysView() }
func createDefaultWeekdaysView() -> some View { HStack(spacing: 0) { ForEach(weekdays, id: \.self, content: createWeekdayItem) }}
func createDefaultWeekDayLabel(_ weekday: MWeekday) -> DefaultWeekdayLabel { DefaultWeekdayLabel(weekday: weekday) }
}

// MARK: - Helpers
public extension WeekdaysView {
/// Creates weekdays view using the selected weekday labels. Cannot be overriden.
func createWeekdaysView() -> some View { HStack(spacing: 0) { ForEach(MWeekday.allCases, id: \.self, content: createWeekdayItem) } }
}
private extension WeekdaysView {
func createWeekdayItem(_ weekday: MWeekday) -> some View { createWeekdayLabel(weekday).frame(maxWidth: .infinity) }
}

// MARK: Helpers
// MARK: - Others
public extension WeekdaysView {
var weekdays: [MWeekday] { MWeekday.allCases }
var body: some View { createContent() }
}

0 comments on commit 37974bb

Please sign in to comment.