From 7cb6922a81c587f9e16d0e1aef5cb8b22356aa47 Mon Sep 17 00:00:00 2001 From: iletai Date: Sat, 4 May 2024 13:17:09 +0700 Subject: [PATCH 1/4] !Refactoring --- .github/workflows/issues_tracker.yml | 95 ++++++ .../CalendarExampleView/ContentView.swift | 4 +- Sources/CalendarView/CalendarView.swift | 293 +++++++++++------- .../Common/CalendarBackground.swift | 19 ++ .../Common/CalendarViewOption.swift | 51 +++ .../CalendarView+ConfigObject.swift | 5 - .../Components/CalendarView+MakeData.swift | 82 ++++- .../Components/CalendarView+RootBuilder.swift | 34 +- .../Components/CalendarViewMode.swift | 21 +- .../Components/CalendarWeekday.swift | 2 + .../CalendarView/Utils/View+Extension.swift | 51 +++ SwiftUICalendarView.podspec | 4 +- 12 files changed, 509 insertions(+), 152 deletions(-) create mode 100644 .github/workflows/issues_tracker.yml create mode 100644 Sources/CalendarView/Common/CalendarBackground.swift create mode 100644 Sources/CalendarView/Common/CalendarViewOption.swift diff --git a/.github/workflows/issues_tracker.yml b/.github/workflows/issues_tracker.yml new file mode 100644 index 0000000..c5905b1 --- /dev/null +++ b/.github/workflows/issues_tracker.yml @@ -0,0 +1,95 @@ +name: Tracker Issues CalendarView. + +on: + issues: + types: [opened, edited] + +jobs: + example_gemini: + name: Example Usable + runs-on: macos-latest + steps: + - name: Get yarn cache directory path + id: yarn-cache-dir-path + run: echo "::set-output name=dir::$(yarn config get cacheFolder)" + + - name: Cache yarn dependencies + id: checkout + uses: actions/cache@v4 + with: + path: ${{ steps.yarn-cache-dir-path.outputs.dir }} + key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} + restore-keys: | + ${{ runner.os }}-yarn- + + - name: Cache npm dependencies + uses: actions/cache@v4 + with: + path: '~/.npm' + key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} + restore-keys: | + ${{ runner.os }}-node- + + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: '20.x' + - name: Install NPM dependencies + run: npm i @google/generative-ai + + - name: Using Scripts + id: scriptgemini + uses: actions/github-script@v7 + continue-on-error: true + env: + APIKEY: ${{ secrets.GEMINI_API_KEY }} + with: + script: | + const modelName = { + model: ["gemini-pro"], + generationConfig: { temperature: 0 }, + }; + const { GenerativeModel } = require("@google/generative-ai"); + const model = new GenerativeModel(process.env.APIKEY, modelName); + const { data: availableLabels } = await github.rest.issues.listLabelsForRepo({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.payload.issue.number, + }); + const prompt = ` + You have a role to manage a GitHub repository. Given an issue information (subject and body), choose suitable labels to it from the labels available for the repository. + Use the following format: + LABELS: "the names of the chosen labels, each name must not be surrounded double quotes, separated by a comma" + Only use the following labels: + \`\`\` + ${availableLabels.map((label) => label.name).join(", ")} + \`\`\` + + ## ISSUE ## + SUBJECT: ${context.payload.issue.title} + BODY: ${context.payload.issue.body} + `; + const result = await model.generateContent(prompt); + const labels = /LABELS\: (.+)/g.exec(result.response.text()); + const label = labels[1].trim().split(/,\s*/); + console.log(label); + return label + - name: Add Labels + uses: actions/github-script@v7 + env: + github-token: ${{ secrets.GITHUB_TOKEN }} + RESULT_GEMINI: ${{ steps.scriptgemini.outputs.result }} + with: + script: | + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.payload.issue.number, + body: `The labels are ${JSON.parse(process.env.RESULT_GEMINI)}` + }); + await github.rest.issues.addLabels({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + labels: JSON.parse(process.env.RESULT_GEMINI) + }); diff --git a/CalendarExampleView/CalendarExampleView/ContentView.swift b/CalendarExampleView/CalendarExampleView/ContentView.swift index b9d4d3e..dd17ca3 100644 --- a/CalendarExampleView/CalendarExampleView/ContentView.swift +++ b/CalendarExampleView/CalendarExampleView/ContentView.swift @@ -38,7 +38,7 @@ struct ContentView: View { }, headerView: { date in HStack { ForEach(date, id: \.self) { - Text($0.weekDayShortName) + Text($0.weekDayShortName.uppercased()) .font(.footnote) .fontWeight(.bold) .foregroundColor( @@ -53,7 +53,7 @@ struct ContentView: View { .font(.footnote) .fontWeight(.semibold) .foregroundColor( - Calendar.current.isDateInWeekend(date) ? .red : .gray + Calendar.current.isDateInWeekend(date) ? .red.opacity(0.4) : .gray ) } .frameInfinity() diff --git a/Sources/CalendarView/CalendarView.swift b/Sources/CalendarView/CalendarView.swift index 02f65d0..ad273db 100644 --- a/Sources/CalendarView/CalendarView.swift +++ b/Sources/CalendarView/CalendarView.swift @@ -9,40 +9,104 @@ import Foundation import SwiftDate import SwiftUI +/** + A SwiftUI view that represents a calendar. + + Use the `CalendarView` struct to display a calendar with customizable date views, header views, and date out views. + + - Parameters: + - DateView: The type of view to use for displaying individual dates. + - HeaderView: The type of view to use for displaying the header containing the month and year. + - DateOutView: The type of view to use for displaying dates outside the current month. + + - Note: The `CalendarView` struct is a generic type that takes three type parameters: `DateView`, `HeaderView`, + and `DateOutView`. + - These type parameters determine the types of views used for displaying dates, + headers, and dates outside the current month, respectively. + + - Note: The `CalendarView` struct conforms to the `View` protocol, which means it can be used as a view in SwiftUI. + + - Note: The `CalendarView` struct is annotated with the `@MainActor` attribute, + which ensures that the view is always accessed from the main actor's context. + + - Note: The `CalendarView` struct has several associated type aliases: `OnSelectedDate`, + `OnEndDragAction`, `YearData`, `MonthDateData`, and `WeekDataData` + . These aliases are used to define the types of closures and data structures used by the `CalendarView`. + + - Note: The `CalendarView` struct has several properties, including + `date`, `calendarOptions`, `dateView`, `headerView`, `dateOutView`, `pinedHeaderView`, `onSelected`, + `isGestureFinished`, and `onDraggingEnded`. + These properties control the behavior and appearance of the calendar view. + + - Note: The `CalendarView` struct has a `body` + property that returns a `View` representing the content of the calendar view. + + - Note: The `CalendarView` struct uses a `ScrollView` and a `LazyVGrid` to display the calendar's content. + The `ScrollView` provides scrolling behavior, while the `LazyVGrid` arranges the date views in a grid layout. + + - Note: The `CalendarView` struct uses a `DragGesture` to detect swipe gestures on the calendar view. + When a swipe gesture is detected, + the `onDraggingEnded` closure is called with the direction of the swipe and the current view mode of the calendar. + + - Note: The `CalendarView` struct provides several modifiers, + such as `marginDefault()`, `background(_:)`, `simultaneousGesture(_:)`, + `scrollIndicators(_:)`, `scrollDisabled(_:)`, and `frameInfinity()`, + that can be used to customize the appearance and behavior of the calendar view. + */ @MainActor public struct CalendarView< DateView: View, HeaderView: View, DateOutView: View >: View { + // MARK: - Type Aliases + /// A closure type that is called when a date is selected. public typealias OnSelectedDate = (Date) -> Void + + /// A closure type that is called when dragging ends. public typealias OnEndDragAction = (Direction, CalendarViewMode) -> Void + + /// A type alias for a dictionary that stores the dates for each year. typealias YearData = [Date: [Date]] + + /// A type alias for an array of dates for a specific month. typealias MonthDateData = [Date] + + /// A type alias for an array of dates for a specific week. typealias WeekDataData = [Date] + // MARK: - Properties + + /// The selected date. var date = Date() - var showHeaders = false - var showDateOut = true - var showDivider = true - var hightLightToDay = true + + /// The options for the calendar view. + var calendarOptions: CalendarViewOption // MARK: - View Builder + + /// The view builder for the date view. let dateView: (Date) -> DateView + + /// The view builder for the header view. let headerView: ([Date]) -> HeaderView + + /// The view builder for the date out view. let dateOutView: (Date) -> DateOutView - var calendar = Calendar.gregorian - var backgroundStatus = Background.hidden - var spacingBetweenDay = 8.0 - var viewMode = CalendarViewMode.month - var spaceBetweenColumns = 8.0 + /// The pinned header view. var pinedHeaderView = PinnedScrollableViews() + + /// The closure that is called when a date is selected. var onSelected: OnSelectedDate = { _ in } + /// The gesture state for tracking the dragging state. @GestureState var isGestureFinished = true + + /// The closure that is called when dragging ends. var onDraggingEnded: OnEndDragAction? + /// The swipe gesture for navigating between dates. private var swipeGesture: some Gesture { DragGesture( minimumDistance: CalendarDefine.kDistaneSwipeBack, @@ -53,52 +117,78 @@ public struct CalendarView< } .onEnded { endedGesture in if (endedGesture.location.x - endedGesture.startLocation.x) > 0 { - onDraggingEnded?(.backward, viewMode) + onDraggingEnded?(.backward, calendarOptions.viewMode) } else { - onDraggingEnded?(.forward, viewMode) + onDraggingEnded?(.forward, calendarOptions.viewMode) } } } + // MARK: - Initializer + + /** + Initializes a new calendar view. + + - Parameters: + - date: The selected date. + - dateView: The view builder for the date view. + - headerView: The view builder for the header view. + - dateOutView: The view builder for the date out view. + */ public init( date: Date, @ViewBuilder dateView: @escaping (Date) -> DateView, @ViewBuilder headerView: @escaping ([Date]) -> HeaderView, - @ViewBuilder dateOutView: @escaping (Date) -> DateOutView, - calendar: Calendar = Calendar.gregorian + @ViewBuilder dateOutView: @escaping (Date) -> DateOutView ) { self.dateView = dateView - self.calendar = calendar self.headerView = headerView self.dateOutView = dateOutView self.date = date + self.calendarOptions = .defaultOption } + // MARK: - Main Body View public var body: some View { ScrollView { LazyVGrid( columns: columnGridLayout, - spacing: spacingBetweenDay, + spacing: calendarOptions.spacingBetweenDay, pinnedViews: pinedHeaderView ) { bodyContentView } .marginDefault() .background(backgroundCalendar) - .highPriorityGesture(swipeGesture) - .onChange(of: isGestureFinished) { _ in } + .simultaneousGesture(swipeGesture) } - .scrollIndicators(viewMode.enableScrollIndicator) - .scrollDisabled(viewMode.isDisableScroll) + .scrollIndicators(calendarOptions.viewMode.enableScrollIndicator) + .scrollDisabled(calendarOptions.viewMode.isDisableScroll) .frameInfinity() } } // MARK: - ViewBuilder Private API +/** + A SwiftUI view representing a calendar view. + + This view displays a calendar with different view modes such as month, year, week, and single day. + The calendar view can be customized with various options + such as showing headers, dividers, highlighting today's date, and more. + + - Author: Tai Le + - Version: 1.4.8 + */ extension CalendarView { + /** + Returns the body content view based on the current view mode. + + The body content view is determined by the `calendarOptions.viewMode` property. + - Returns: A SwiftUI `View` representing the body content. + */ @ViewBuilder private var bodyContentView: some View { - switch viewMode { + switch calendarOptions.viewMode { case .month: monthContentView() case .year: @@ -110,12 +200,18 @@ extension CalendarView { } } + /** + Returns the year content view. + + The year content view displays the calendar organized by months. + - Returns: A SwiftUI `View` representing the year content. + */ @ViewBuilder fileprivate func yearContentView() -> some View { ForEach(yearData.keys.sorted(), id: \.self) { month in Section( header: - LazyVStack { + LazyVStack(alignment: .center) { HStack { Spacer() Text(month.monthName(.defaultStandalone) + " \(month.year)") @@ -123,10 +219,10 @@ extension CalendarView { .fontWeight(.bold) Spacer() } - .opacity(showHeaders ? 1.0 : 0.0) - if showDivider { - Divider() - } + .allowVisibleWith(calendarOptions.isShowHeader) + Divider() + .allowVisibleWith(calendarOptions.isShowDivider) + .padding(.bottom, 4) headerView(headerDates) } .maxWidthAble() @@ -137,16 +233,23 @@ extension CalendarView { ) { date in if date.compare(.isSameMonth(month)) { dateView(date) - .hightLightToDayView(date.isToday && hightLightToDay) + .hightLightToDayView(date.isToday && calendarOptions.isShowHightLightToDay) } else { dateOutView(date) - .opacity(showDateOut ? 1.0 : 0.0) + .allowVisibleWith(calendarOptions.isShowDateOut) } } } } } + /** + Returns the month title view for a given month. + + The month title view displays the name of the month and the year. + - Parameter month: The month for which to display the title. + - Returns: A SwiftUI `View` representing the month title. + */ @ViewBuilder fileprivate func monthTitle(for month: Date) -> some View { HStack { @@ -156,143 +259,97 @@ extension CalendarView { .fontWeight(.bold) Spacer() } - .opacity(showHeaders ? 1.0 : 0.0) + .allowVisibleWith(calendarOptions.isShowHeader) } + /** + Returns the background calendar view. + + The background calendar view displays the background color and corner radius of the calendar. + - Returns: A SwiftUI `View` representing the background calendar. + */ @ViewBuilder fileprivate var backgroundCalendar: some View { - if case let .visible(conner, backgroundColor) = backgroundStatus { + if case let .visible(conner, backgroundColor) = calendarOptions.backgroundStatus { backgroundColor.withRounderConner(conner) } } + /** + Returns the calendar week view. + + The calendar week view displays the calendar organized by weeks. + - Returns: A SwiftUI `View` representing the calendar week view. + */ @ViewBuilder fileprivate func calendarWeekView() -> some View { Section(header: weekDayAndMonthView) { ForEach(weekData, id: \.self) { date in if date.compare(.isSameWeek(self.date)) { dateView(date) - .hightLightToDayView(date.isToday && hightLightToDay) + .hightLightToDayView(date.isToday && calendarOptions.isShowHightLightToDay) } else { dateOutView(date) - .opacity(showDateOut ? 1.0 : 0.0) + .allowVisibleWith(calendarOptions.isShowDateOut) } } } } + /** + Returns the month content view. + + The month content view displays the calendar organized by months. + - Returns: A SwiftUI `View` representing the month content. + */ @ViewBuilder fileprivate func monthContentView() -> some View { Section(header: weekDayAndMonthView) { ForEach(monthData, id: \.self) { date in if date.compare(.isSameMonth(self.date)) { dateView(date) - .hightLightToDayView(date.isToday && hightLightToDay) + .hightLightToDayView(date.isToday && calendarOptions.isShowHightLightToDay) } else { dateOutView(date) - .opacity(showDateOut ? 1.0 : 0.0) + .allowVisibleWith(calendarOptions.isShowDateOut) } } } } + /** + Returns the week day and month view. + + The week day and month view displays the month title, divider, and header view. + - Returns: A SwiftUI `View` representing the week day and month view. + */ @ViewBuilder private var weekDayAndMonthView: some View { VStack { monthTitle(for: date) - if showDivider { - Divider() - } + Divider() + .allowVisibleWith(calendarOptions.isShowDivider) + .padding(.bottom, 4) headerView(headerDates) } } + /** + Returns the single day content view. + + The single day content view displays the header view and the date view for a single day. + - Returns: A SwiftUI `View` representing the single day content. + */ @ViewBuilder private func singleDayContentView() -> some View { - VStack(spacing: 0) { - Text(date.dayName) - .font(.headline) - Text(date.toString(.date(.full))) - .font(.headline) - .maxWidthAble() - .maxHeightAble() + VStack { + headerView(headerDates) + Divider() + .allowVisibleWith(calendarOptions.isShowDivider) + dateView(date) + .hightLightToDayView(date.isToday && calendarOptions.isShowHightLightToDay) } .maxWidthAble() .maxHeightAble() } } - -extension View { - @ViewBuilder - func hightLightToDayView(_ isToday: Bool, _ color: Color = .orange) -> some View { - if isToday { - background(color.clipShape(Circle())) - } else { - self - } - } -} - -// MARK: - Data For Calendar -extension CalendarView { - fileprivate var yearData: YearData { - let dates = DateInRegion.enumerateDates( - from: date.startOfYear(calendar), - to: date.endOfYear(calendar), - increment: DateComponents(month: 1) - ) - .map { - $0.date - } - return dates.reduce(into: [:]) { month, date in - month[date] = generateDates( - date: date.startOfMonth(calendar).date, - dateComponents: CalendarViewMode.month.dateComponent - ) - } - } - - fileprivate var columnGridLayout: [GridItem] { - switch viewMode { - case .single: - return Array( - repeating: GridItem(.flexible()), - count: 1 - ) - default: - return Array( - repeating: GridItem(.flexible(), spacing: spaceBetweenColumns), - count: CalendarDefine.kWeekDays - ) - } - } - - fileprivate var monthData: MonthDateData { - generateDates( - date: date, - withComponent: .month, - dateComponents: DateComponents(day: 1) - ) - } - - fileprivate var weekData: WeekDataData { - generateDates( - date: date, - withComponent: .weekOfMonth, - dateComponents: DateComponents(day: 1) - ) - } - - fileprivate var headerDates: [Date] { - switch viewMode { - case .month, .week: - return Array(monthData.prefix(CalendarDefine.kWeekDays)) - case .year: - return Array( - yearData[date.dateAtStartOf(.year), default: []].prefix(CalendarDefine.kWeekDays) - ) - case .single: - return [date] - } - } -} diff --git a/Sources/CalendarView/Common/CalendarBackground.swift b/Sources/CalendarView/Common/CalendarBackground.swift new file mode 100644 index 0000000..2184a46 --- /dev/null +++ b/Sources/CalendarView/Common/CalendarBackground.swift @@ -0,0 +1,19 @@ +// +// CalendarBackground.swift +// +// +// Created by Lê Quang Trọng Tài on 5/4/24. +// + +import Foundation +import SwiftUI + +/// An enumeration representing the background options for a calendar view. +public enum CalendarBackground { + /// The background is hidden. + case hidden + /// The background is visible with a specific opacity and color. + case visible(CGFloat, Color) + /// The background is an image with the specified name. + case image(String) +} diff --git a/Sources/CalendarView/Common/CalendarViewOption.swift b/Sources/CalendarView/Common/CalendarViewOption.swift new file mode 100644 index 0000000..1bc2a8a --- /dev/null +++ b/Sources/CalendarView/Common/CalendarViewOption.swift @@ -0,0 +1,51 @@ +// +// CalendarViewOption.swift +// +// +// Created by Lê Quang Trọng Tài on 5/4/24. +// + +import Foundation + +/// A struct that represents the options for a calendar view. +public struct CalendarViewOption { + public var isShowHeader: Bool + public var isShowDateOut: Bool + public var isShowDivider: Bool + public var isShowHightLightToDay: Bool + public var calendar: Calendar + public var backgroundStatus: CalendarBackground + public var spacingBetweenDay: CGFloat + public var viewMode: CalendarViewMode + public var spaceBetweenColumns: CGFloat + + /// Initializes a new instance of `CalendarViewOption` with default values. + init() { + self.isShowHeader = true + self.isShowDateOut = true + self.isShowDivider = true + self.isShowHightLightToDay = true + self.calendar = .gregorian + self.backgroundStatus = .hidden + self.spacingBetweenDay = 8.0 + self.viewMode = .year + self.spaceBetweenColumns = 8.0 + } +} + +public extension CalendarViewOption { + /// The default `CalendarViewOption` instance. + static var defaultOption: CalendarViewOption { + var options = CalendarViewOption() + options.backgroundStatus = .hidden + options.calendar = .gregorian + options.isShowHightLightToDay = true + options.isShowDateOut = true + options.isShowHeader = true + options.spaceBetweenColumns = 8.0 + options.spacingBetweenDay = 8.0 + options.viewMode = .year + options.isShowDivider = true + return options + } +} diff --git a/Sources/CalendarView/Components/CalendarView+ConfigObject.swift b/Sources/CalendarView/Components/CalendarView+ConfigObject.swift index 7657585..009fb0a 100644 --- a/Sources/CalendarView/Components/CalendarView+ConfigObject.swift +++ b/Sources/CalendarView/Components/CalendarView+ConfigObject.swift @@ -16,9 +16,4 @@ extension CalendarView { /// Swiping from right to left case backward } - - public enum Background { - case hidden - case visible(CGFloat, Color) - } } diff --git a/Sources/CalendarView/Components/CalendarView+MakeData.swift b/Sources/CalendarView/Components/CalendarView+MakeData.swift index 07d267e..396474f 100644 --- a/Sources/CalendarView/Components/CalendarView+MakeData.swift +++ b/Sources/CalendarView/Components/CalendarView+MakeData.swift @@ -7,23 +7,31 @@ import Foundation import SwiftDate +import SwiftUI extension CalendarView { + /// Generates an array of dates based on the given parameters. + /// + /// - Parameters: + /// - date: The base date. + /// - withComponent: The calendar component to generate dates for. Default is `.month`. + /// - dateComponents: The date components to increment by. + /// - Returns: An array of dates. func generateDates( date: Date, withComponent: Calendar.Component = .month, dateComponents: DateComponents ) -> [Date] { - SwiftDate.defaultRegion = Region(calendar: calendar) + SwiftDate.defaultRegion = Region(calendar: calendarOptions.calendar) let dateStart = date.dateAtStartOf(withComponent) let dateEnd = date.dateAtEndOf(withComponent) let dateStartRegion = DateInRegion( dateStart.dateAt(.startOfWeek), - region: .currentIn(calendar: calendar) + region: .currentIn(calendar: calendarOptions.calendar) ) let dateEndRegion = DateInRegion( dateEnd.dateAt(.endOfWeek), - region: .currentIn(calendar: calendar) + region: .currentIn(calendar: calendarOptions.calendar) ) let dates = DateInRegion.enumerateDates( from: dateStartRegion, @@ -32,5 +40,73 @@ extension CalendarView { ).map { $0.date } return dates } +} + +// MARK: - Data For Calendar +extension CalendarView { + /// Computes the year data for the calendar. + var yearData: YearData { + DateInRegion.enumerateDates( + from: date.startOfYear(calendarOptions.calendar), + to: date.endOfYear(calendarOptions.calendar), + increment: DateComponents(month: 1) + ) + .map { + $0.date + } + .reduce(into: [:]) { month, date in + month[date] = generateDates( + date: date.startOfMonth(calendarOptions.calendar).date, + dateComponents: CalendarViewMode.month.dateComponent + ) + } + } + + /// Computes the grid layout for the calendar columns. + var columnGridLayout: [GridItem] { + switch calendarOptions.viewMode { + case .single: + return Array( + repeating: GridItem(.flexible()), + count: 1 + ) + default: + return Array( + repeating: GridItem(.flexible(), spacing: calendarOptions.spaceBetweenColumns), + count: CalendarDefine.kWeekDays + ) + } + } + /// Computes the month data for the calendar. + var monthData: MonthDateData { + generateDates( + date: date, + withComponent: .month, + dateComponents: DateComponents(day: 1) + ) + } + + /// Computes the week data for the calendar. + var weekData: WeekDataData { + generateDates( + date: date, + withComponent: .weekOfMonth, + dateComponents: DateComponents(day: 1) + ) + } + + /// Computes the header dates for the calendar. + var headerDates: [Date] { + switch calendarOptions.viewMode { + case .month, .week: + return Array(monthData.prefix(CalendarDefine.kWeekDays)) + case .year: + return Array( + yearData[date.dateAtStartOf(.year), default: []].prefix(CalendarDefine.kWeekDays) + ) + case .single: + return [date] + } + } } diff --git a/Sources/CalendarView/Components/CalendarView+RootBuilder.swift b/Sources/CalendarView/Components/CalendarView+RootBuilder.swift index 3dd592f..08e1c1f 100644 --- a/Sources/CalendarView/Components/CalendarView+RootBuilder.swift +++ b/Sources/CalendarView/Components/CalendarView+RootBuilder.swift @@ -14,56 +14,56 @@ extension CalendarView: RootBuilder { /// - Parameter isEnable: A boolean value indicating whether to enable or disable the header. /// - Returns: An instance of `Self` with the updated configuration. public func enableHeader(_ isEnable: Bool) -> Self { - mutating(\.showHeaders, value: isEnable) + mutating(\.calendarOptions.isShowHeader, value: isEnable) } /// Enables or disables the display of dates outside the current month in the calendar view. /// - Parameter isShow: A boolean value indicating whether to show or hide dates outside the current month. /// - Returns: An instance of `Self` with the updated configuration. public func enableDateOut(_ isShow: Bool) -> Self { - mutating(\.showDateOut, value: isShow) + mutating(\.calendarOptions.isShowDateOut, value: isShow) } /// Sets the background style for the calendar view. /// - Parameter status: The background style for the calendar view. /// - Returns: An instance of `Self` with the updated configuration. - public func background(_ status: Background) -> Self { - mutating(\.backgroundStatus, value: status) + public func background(_ status: CalendarBackground) -> Self { + mutating(\.calendarOptions.backgroundStatus, value: status) } /// Sets the spacing between rows in the calendar view. /// - Parameter spacing: The spacing between rows. /// - Returns: An instance of `Self` with the updated configuration. public func rowsSpacing(_ spacing: CGFloat) -> Self { - mutating(\.spacingBetweenDay, value: spacing) + mutating(\.calendarOptions.spacingBetweenDay, value: spacing) } /// Sets the spacing between columns in the calendar view. /// - Parameter spacing: The spacing between columns. /// - Returns: An instance of `Self` with the updated configuration. public func columnSpacing(_ spacing: CGFloat) -> Self { - mutating(\.spaceBetweenColumns, value: spacing) + mutating(\.calendarOptions.spaceBetweenColumns, value: spacing) } /// Sets the first day of the week in the calendar view. /// - Parameter first: The index of the first day of the week (1 for Sunday, 2 for Monday, etc.). /// - Returns: An instance of `Self` with the updated configuration. public func firstWeekDay(_ first: CalendarWeekday) -> Self { - mutating(\.calendar.firstWeekday, value: first.rawValue) + mutating(\.calendarOptions.calendar.firstWeekday, value: first.rawValue) } /// Sets the locale for the calendar view. /// - Parameter locale: The locale to be used for the calendar view. /// - Returns: An instance of `Self` with the updated configuration. public func calendarLocate(locale: Locale) -> Self { - mutating(\.calendar.locale, value: locale) + mutating(\.calendarOptions.calendar.locale, value: locale) } /// Sets the view mode for the calendar view. /// - Parameter mode: The view mode for the calendar view. /// - Returns: An instance of `Self` with the updated configuration. public func setViewMode(_ mode: CalendarViewMode) -> Self { - mutating(\.viewMode, value: mode) + mutating(\.calendarOptions.viewMode, value: mode) } /// Sets the callback for when dragging ends in the calendar view. @@ -80,18 +80,30 @@ extension CalendarView: RootBuilder { mutating(\.pinedHeaderView, value: [view]) } + /// Sets a callback closure to be executed when a date is selected in the calendar view. + /// - Parameter callback: The closure to be executed when a date is selected. + /// - Returns: The modified `CalendarView+RootBuilder` instance. public func onSelectDate(_ callback: @escaping OnSelectedDate) -> Self { mutating(\.onSelected, value: callback) } + /// Enables or disables the divider in the calendar view. + /// - Parameter isEnable: A boolean value indicating whether the divider should be enabled or disabled. + /// - Returns: The modified `CalendarView+RootBuilder` instance. public func enableDivider(_ isEnable: Bool) -> Self { - mutating(\.showDivider, value: isEnable) + mutating(\.calendarOptions.isShowDivider, value: isEnable) } + /// Enables or disables the highlight effect on the current day in the calendar view. + /// - Parameter isEnable: A boolean value indicating whether the highlight effect should be enabled or disabled. + /// - Returns: The modified `CalendarView+RootBuilder` instance. public func enableHighlightToDay(_ isEnable: Bool) -> Self { - mutating(\.hightLightToDay, value: isEnable) + mutating(\.calendarOptions.isShowHightLightToDay, value: isEnable) } + /// Sets the initial date to be displayed in the calendar view. + /// - Parameter date: The initial date to be displayed. + /// - Returns: The modified `CalendarView+RootBuilder` instance. func setDate(_ date: Date) -> Self { mutating(\.date, value: date) } diff --git a/Sources/CalendarView/Components/CalendarViewMode.swift b/Sources/CalendarView/Components/CalendarViewMode.swift index 1dbdaf3..7d1bf0b 100644 --- a/Sources/CalendarView/Components/CalendarViewMode.swift +++ b/Sources/CalendarView/Components/CalendarViewMode.swift @@ -9,12 +9,14 @@ import Foundation import SwiftUI import SwiftDate +/// Represents the different modes of the calendar view. public enum CalendarViewMode: CaseIterable { case month case week case year case single + /// The corresponding `Calendar.Component` for each mode. var component: Calendar.Component { switch self { case .month: @@ -28,43 +30,40 @@ public enum CalendarViewMode: CaseIterable { } } + /// The corresponding `DateComponents` for each mode. var dateComponent: DateComponents { switch self { - case .month, - .single, - .week: + case .month, .single, .week: return DateComponents(day: 1) case .year: return DateComponents(month: 1) } } + /// Determines if scrolling is enabled for the mode. var enableScroll: Bool { switch self { - case .month: - return false - case .week: + case .month, .week, .single: return false case .year: return true - case .single: - return false } } + /// Determines if scrolling is disabled for the mode. var isDisableScroll: Bool { !enableScroll } + /// The visibility of the scroll indicator for the mode. var enableScrollIndicator: ScrollIndicatorVisibility { switch self { - case .month, - .single, - .week: + case .month, .week, .single: return .never case .year: return .visible } } + /// The type of date related to the mode. var dateRelatedType: DateRelatedType { switch self { case .month: diff --git a/Sources/CalendarView/Components/CalendarWeekday.swift b/Sources/CalendarView/Components/CalendarWeekday.swift index 812bae8..e0bf77f 100644 --- a/Sources/CalendarView/Components/CalendarWeekday.swift +++ b/Sources/CalendarView/Components/CalendarWeekday.swift @@ -7,6 +7,7 @@ import Foundation +/// Represents the days of the week in a calendar. public enum CalendarWeekday: Int, CustomStringConvertible { case sunday = 1 case monday @@ -16,6 +17,7 @@ public enum CalendarWeekday: Int, CustomStringConvertible { case friday case saturday + /// A textual representation of the weekday. public var description: String { switch self { case .sunday: diff --git a/Sources/CalendarView/Utils/View+Extension.swift b/Sources/CalendarView/Utils/View+Extension.swift index c328d00..00a2136 100644 --- a/Sources/CalendarView/Utils/View+Extension.swift +++ b/Sources/CalendarView/Utils/View+Extension.swift @@ -9,23 +9,74 @@ import Foundation import SwiftUI extension View { + /// Sets the maximum width of the view to infinity. + /// + /// - Returns: A modified view with the maximum width set to infinity. public func maxWidthAble() -> some View { frame(maxWidth: .infinity) } + /// Sets the maximum height of the view to infinity. + /// + /// - Returns: A modified view with the maximum height set to infinity. public func maxHeightAble() -> some View { frame(maxHeight: .infinity) } + /// Sets both the maximum width and maximum height of the view to infinity. + /// + /// - Returns: A modified view with both the maximum width and maximum height set to infinity. public func frameInfinity() -> some View { maxWidthAble().maxHeightAble() } + /// Sets the padding of the view to a default value of 16 on all sides. + /// + /// - Returns: A modified view with the padding set to a default value of 16 on all sides. public func marginDefault() -> some View { padding(.all, 16) } + /// Clips the view to the specified corner radius. + /// + /// - Parameter radius: The corner radius to apply to the view. + /// - Returns: A modified view with the specified corner radius applied. public func withRounderConner(_ radius: CGFloat) -> some View { clipShape(RoundedRectangle(cornerRadius: radius)) } } + +extension View { + /** + Highlights the day view if it is today. + + This modifier applies a background color to the view if the date is today. + - Parameters: + - isToday: A boolean value indicating whether the date is today. + - color: The color to use for highlighting. Default is `.orange`. + - Returns: A modified SwiftUI `View` with the highlighting applied. + */ + @ViewBuilder + func hightLightToDayView( + _ isToday: Bool, + _ color: Color = .orange + ) -> some View { + if isToday { + background(color.clipShape(Circle())) + } else { + self + } + } + + /** + Sets the visibility of the view based on a boolean value. + + This modifier sets the opacity of the view to 1.0 if the `isAllow` parameter is `true`, otherwise sets it to 0.0. + - Parameter isAllow: A boolean value indicating whether the view should be visible. + - Returns: A modified SwiftUI `View` with the visibility set. + */ + @ViewBuilder + func allowVisibleWith(_ isAllow: Bool) -> some View { + opacity(isAllow ? 1.0 : 0.0) + } +} diff --git a/SwiftUICalendarView.podspec b/SwiftUICalendarView.podspec index 736dc1c..1c9e432 100644 --- a/SwiftUICalendarView.podspec +++ b/SwiftUICalendarView.podspec @@ -1,11 +1,11 @@ Pod::Spec.new do |s| s.name = 'SwiftUICalendarView' - s.summary = 'Create fully customisable calendar in no time. Keep your code clean' + s.summary = 'Create fully customizable calendar in no time. Keep your code clean' s.description = <<-DESC SwiftUICalendarView is a free and open-source library in SwiftUI to make calendar. DESC - s.version = '1.4.5' + s.version = '1.4.9' s.platform = :ios s.ios.deployment_target = '16.0' # Updated deployment target to a valid iOS version s.swift_version = '5.9' From ca6b0cbec00dd09e0a8b1dbb6eeb159fa7d5bce6 Mon Sep 17 00:00:00 2001 From: iletai Date: Sat, 4 May 2024 17:38:09 +0700 Subject: [PATCH 2/4] !Refactoring --- .../CalendarExampleView/ContentView.swift | 140 +++++++++--------- Sources/CalendarView/CalendarView.swift | 25 ++-- 2 files changed, 82 insertions(+), 83 deletions(-) diff --git a/CalendarExampleView/CalendarExampleView/ContentView.swift b/CalendarExampleView/CalendarExampleView/ContentView.swift index dd17ca3..224a454 100644 --- a/CalendarExampleView/CalendarExampleView/ContentView.swift +++ b/CalendarExampleView/CalendarExampleView/ContentView.swift @@ -21,76 +21,82 @@ struct ContentView: View { @State var isHightLightToDay = true var body: some View { VStack { - CalendarView( - date: selectedDate - , dateView: { date in - VStack { - Text(date.dayName) - .font(.footnote) - .fontWeight(.semibold) - .foregroundColor( - Calendar.current.isDateInWeekend(date) ? .red : .black - ) - } - .frameInfinity() - .frame(height: 30) - .background(listSelectedDate.contains(date) ? .cyan : .clear) - }, headerView: { date in - HStack { - ForEach(date, id: \.self) { - Text($0.weekDayShortName.uppercased()) - .font(.footnote) - .fontWeight(.bold) - .foregroundColor( - Calendar.current.isDateInWeekend($0) ? .red : .black - ) - .frame(maxWidth: .infinity) + ScrollView { + VStack { + CalendarView( + date: selectedDate + , dateView: { date in + VStack { + Text(date.dayName) + .font(.footnote) + .fontWeight(.semibold) + .foregroundColor( + Calendar.current.isDateInWeekend(date) ? .red : .black + ) + } + .frameInfinity() + .frame(height: 30) + .background(listSelectedDate.contains(date) ? .cyan : .clear) + }, headerView: { date in + HStack { + ForEach(date, id: \.self) { + Text($0.weekDayShortName.uppercased()) + .font(.footnote) + .fontWeight(.bold) + .foregroundColor( + Calendar.current.isDateInWeekend($0) ? .red : .black + ) + .frame(maxWidth: .infinity) + } + } + }, dateOutView: { date in + VStack { + Text(date.dayName) + .font(.footnote) + .fontWeight(.semibold) + .foregroundColor( + Calendar.current.isDateInWeekend(date) ? .red.opacity(0.4) : .gray + ) + } + .frameInfinity() + .frame(height: 30) + .background(listSelectedDate.contains(date) ? .cyan : .clear) + } + ) + .enableHeader(isShowHeader) + .enableDateOut(isShowDateOut) + .firstWeekDay(firstWeekDate) + .calendarLocate(locale: Locales.vietnamese.toLocale()) + .enablePinedView([.sectionHeaders, .sectionFooters]) + .setViewMode(viewMode) + .rowsSpacing(8) + .columnSpacing(8) + .background(.visible(12, .gray.opacity(0.1))) + .onDraggingEnded { direction, viewMode in + if direction == .forward { + withAnimation(.easeInOut) { + selectedDate = selectedDate.dateAt( + viewMode == .month ? .nextMonth : .nextWeek + ).date + } + } else { + withAnimation(.easeInOut) { + selectedDate = selectedDate.dateAt( + viewMode == .month ? .prevMonth : .prevWeek + ).date + } } } - }, dateOutView: { date in - VStack { - Text(date.dayName) - .font(.footnote) - .fontWeight(.semibold) - .foregroundColor( - Calendar.current.isDateInWeekend(date) ? .red.opacity(0.4) : .gray - ) - } - .frameInfinity() - .frame(height: 30) - .background(listSelectedDate.contains(date) ? .cyan : .clear) - } - ) - .enableHeader(isShowHeader) - .enableDateOut(isShowDateOut) - .firstWeekDay(firstWeekDate) - .calendarLocate(locale: Locales.vietnamese.toLocale()) - .enablePinedView([.sectionHeaders, .sectionFooters]) - .setViewMode(viewMode) - .rowsSpacing(8) - .columnSpacing(8) - .background(.visible(12, .gray.opacity(0.1))) - .onDraggingEnded { direction, viewMode in - if direction == .forward { - withAnimation(.easeInOut) { - selectedDate = selectedDate.dateAt( - viewMode == .month ? .nextMonth : .nextWeek - ).date - } - } else { - withAnimation(.easeInOut) { - selectedDate = selectedDate.dateAt( - viewMode == .month ? .prevMonth : .prevWeek - ).date - } + .onSelectDate(onSelectedDate) + .enableDivider(isShowDivider) + .enableHighlightToDay(isHightLightToDay) + .marginDefault() + .allowsTightening(true) + Spacer() + } + .frame(maxWidth: .infinity) } - .onSelectDate(onSelectedDate) - .enableDivider(isShowDivider) - .enableHighlightToDay(isHightLightToDay) - .marginDefault() - .allowsTightening(true) - Spacer() VStack { listButtonDemo .padding() @@ -103,9 +109,7 @@ struct ContentView: View { .frame(width: 300) .padding() } - } - .frame(maxWidth: .infinity) } var listButtonDemo: some View { diff --git a/Sources/CalendarView/CalendarView.swift b/Sources/CalendarView/CalendarView.swift index ad273db..925273d 100644 --- a/Sources/CalendarView/CalendarView.swift +++ b/Sources/CalendarView/CalendarView.swift @@ -150,21 +150,16 @@ public struct CalendarView< // MARK: - Main Body View public var body: some View { - ScrollView { - LazyVGrid( - columns: columnGridLayout, - spacing: calendarOptions.spacingBetweenDay, - pinnedViews: pinedHeaderView - ) { - bodyContentView - } - .marginDefault() - .background(backgroundCalendar) - .simultaneousGesture(swipeGesture) + LazyVGrid( + columns: columnGridLayout, + spacing: calendarOptions.spacingBetweenDay, + pinnedViews: pinedHeaderView + ) { + bodyContentView } - .scrollIndicators(calendarOptions.viewMode.enableScrollIndicator) - .scrollDisabled(calendarOptions.viewMode.isDisableScroll) - .frameInfinity() + .highPriorityGesture(swipeGesture) + .marginDefault() + .background(backgroundCalendar) } } @@ -211,7 +206,7 @@ extension CalendarView { ForEach(yearData.keys.sorted(), id: \.self) { month in Section( header: - LazyVStack(alignment: .center) { + LazyVStack(alignment: .leading) { HStack { Spacer() Text(month.monthName(.defaultStandalone) + " \(month.year)") From 76e2c3c02181857a90fcc81da843ae5493c9d630 Mon Sep 17 00:00:00 2001 From: iletai Date: Sun, 16 Jun 2024 22:57:53 +0700 Subject: [PATCH 3/4] + add compact mode year view --- .../project.pbxproj | 4 ++ .../CalendarExampleView/ContentView.swift | 28 +++++++++--- Sources/CalendarView/CalendarView.swift | 45 ++++++++++++++++++- .../Common/CalendarViewOption.swift | 4 +- .../Components/CalendarView+MakeData.swift | 13 ++++++ .../Components/CalendarViewMode.swift | 15 ++++++- 6 files changed, 96 insertions(+), 13 deletions(-) diff --git a/CalendarExampleView/CalendarExampleView.xcodeproj/project.pbxproj b/CalendarExampleView/CalendarExampleView.xcodeproj/project.pbxproj index 7a93f6f..6b455c9 100644 --- a/CalendarExampleView/CalendarExampleView.xcodeproj/project.pbxproj +++ b/CalendarExampleView/CalendarExampleView.xcodeproj/project.pbxproj @@ -287,6 +287,8 @@ DEVELOPMENT_TEAM = AP58YLHQ2S; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_CFBundleDisplayName = CalendarExample; + INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.lifestyle"; INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UILaunchScreen_Generation = YES; @@ -316,6 +318,8 @@ DEVELOPMENT_TEAM = AP58YLHQ2S; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_CFBundleDisplayName = CalendarExample; + INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.lifestyle"; INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UILaunchScreen_Generation = YES; diff --git a/CalendarExampleView/CalendarExampleView/ContentView.swift b/CalendarExampleView/CalendarExampleView/ContentView.swift index 224a454..9afe380 100644 --- a/CalendarExampleView/CalendarExampleView/ContentView.swift +++ b/CalendarExampleView/CalendarExampleView/ContentView.swift @@ -14,11 +14,28 @@ struct ContentView: View { @State var isShowDateOut = false @State var firstWeekDate = CalendarWeekday.monday @State var isShowDivider = false - @State var viewMode = CalendarViewMode.year + @State var viewMode = CalendarViewMode.year(.full) @State private var selectedDate = Date() @State private var colorDay = Color.white @State var listSelectedDate = [Date]() @State var isHightLightToDay = true + + var fontDate: Font { + switch viewMode { + case .month, + .week, + .single: + return .footnote + case .year(let yearDisplayMode): + switch yearDisplayMode { + case .compact: + return .system(size: 10, weight: .regular) + case .full: + return .footnote.weight(.semibold) + } + } + } + var body: some View { VStack { ScrollView { @@ -28,8 +45,7 @@ struct ContentView: View { , dateView: { date in VStack { Text(date.dayName) - .font(.footnote) - .fontWeight(.semibold) + .font(fontDate) .foregroundColor( Calendar.current.isDateInWeekend(date) ? .red : .black ) @@ -41,8 +57,7 @@ struct ContentView: View { HStack { ForEach(date, id: \.self) { Text($0.weekDayShortName.uppercased()) - .font(.footnote) - .fontWeight(.bold) + .font(fontDate) .foregroundColor( Calendar.current.isDateInWeekend($0) ? .red : .black ) @@ -52,8 +67,7 @@ struct ContentView: View { }, dateOutView: { date in VStack { Text(date.dayName) - .font(.footnote) - .fontWeight(.semibold) + .font(fontDate) .foregroundColor( Calendar.current.isDateInWeekend(date) ? .red.opacity(0.4) : .gray ) diff --git a/Sources/CalendarView/CalendarView.swift b/Sources/CalendarView/CalendarView.swift index 925273d..705d62c 100644 --- a/Sources/CalendarView/CalendarView.swift +++ b/Sources/CalendarView/CalendarView.swift @@ -186,8 +186,13 @@ extension CalendarView { switch calendarOptions.viewMode { case .month: monthContentView() - case .year: - yearContentView() + case .year(let displayMode): + switch displayMode { + case .compact: + yearContentCompactView() + case .full: + yearContentView() + } case .week: calendarWeekView() case .single: @@ -238,6 +243,42 @@ extension CalendarView { } } + @ViewBuilder + fileprivate func yearContentCompactView() -> some View { + ForEach(yearData.keys.sorted(), id: \.self) { month in + LazyVStack(alignment: .leading, spacing: .zero) { + HStack { + Text(month.monthName(.short)) + .font(.system(size: 10)) + .fontWeight(.regular) + Spacer() + } + .allowVisibleWith(calendarOptions.isShowHeader) + Divider() + .allowVisibleWith(calendarOptions.isShowDivider) + .padding(.bottom, 2) + LazyVGrid(columns: Array( + repeating: GridItem(.flexible(), spacing: 0, alignment: .top), + count: CalendarDefine.kWeekDays + ), alignment: .leading, spacing: .zero + ) { + ForEach( + yearData[month, default: []], + id: \.self + ) { date in + if date.compare(.isSameMonth(month)) { + dateView(date) + .hightLightToDayView(date.isToday && calendarOptions.isShowHightLightToDay) + } else { + dateOutView(date) + .allowVisibleWith(calendarOptions.isShowDateOut) + } + } + } + } + } + } + /** Returns the month title view for a given month. diff --git a/Sources/CalendarView/Common/CalendarViewOption.swift b/Sources/CalendarView/Common/CalendarViewOption.swift index 1bc2a8a..20a6ad2 100644 --- a/Sources/CalendarView/Common/CalendarViewOption.swift +++ b/Sources/CalendarView/Common/CalendarViewOption.swift @@ -28,7 +28,7 @@ public struct CalendarViewOption { self.calendar = .gregorian self.backgroundStatus = .hidden self.spacingBetweenDay = 8.0 - self.viewMode = .year + self.viewMode = .year(.full) self.spaceBetweenColumns = 8.0 } } @@ -44,7 +44,7 @@ public extension CalendarViewOption { options.isShowHeader = true options.spaceBetweenColumns = 8.0 options.spacingBetweenDay = 8.0 - options.viewMode = .year + options.viewMode = .year(.full) options.isShowDivider = true return options } diff --git a/Sources/CalendarView/Components/CalendarView+MakeData.swift b/Sources/CalendarView/Components/CalendarView+MakeData.swift index 396474f..22cde9a 100644 --- a/Sources/CalendarView/Components/CalendarView+MakeData.swift +++ b/Sources/CalendarView/Components/CalendarView+MakeData.swift @@ -70,6 +70,19 @@ extension CalendarView { repeating: GridItem(.flexible()), count: 1 ) + case .year(let mode): + switch mode { + case .compact: + return Array( + repeating: GridItem(.flexible(), alignment: .top), + count: 2 + ) + case .full: + return Array( + repeating: GridItem(.flexible(), spacing: calendarOptions.spaceBetweenColumns), + count: CalendarDefine.kWeekDays + ) + } default: return Array( repeating: GridItem(.flexible(), spacing: calendarOptions.spaceBetweenColumns), diff --git a/Sources/CalendarView/Components/CalendarViewMode.swift b/Sources/CalendarView/Components/CalendarViewMode.swift index 7d1bf0b..c4a7937 100644 --- a/Sources/CalendarView/Components/CalendarViewMode.swift +++ b/Sources/CalendarView/Components/CalendarViewMode.swift @@ -10,10 +10,14 @@ import SwiftUI import SwiftDate /// Represents the different modes of the calendar view. -public enum CalendarViewMode: CaseIterable { +public enum CalendarViewMode: CaseIterable, Hashable { + public static var allCases: [CalendarViewMode] { + [CalendarViewMode.year(.full), CalendarViewMode.year(.compact), CalendarViewMode.month, CalendarViewMode.single] + } + case month case week - case year + case year(YearDisplayMode) case single /// The corresponding `Calendar.Component` for each mode. @@ -77,3 +81,10 @@ public enum CalendarViewMode: CaseIterable { } } } + +extension CalendarViewMode: Equatable {} + +public enum YearDisplayMode { + case compact + case full +} From 534d7788a7aece6eaea14c0092705ac45983659a Mon Sep 17 00:00:00 2001 From: iletai Date: Sun, 16 Jun 2024 23:01:58 +0700 Subject: [PATCH 4/4] * Fix lint --- .../CalendarExampleView/ContentView.swift | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/CalendarExampleView/CalendarExampleView/ContentView.swift b/CalendarExampleView/CalendarExampleView/ContentView.swift index 9afe380..fca855d 100644 --- a/CalendarExampleView/CalendarExampleView/ContentView.swift +++ b/CalendarExampleView/CalendarExampleView/ContentView.swift @@ -22,17 +22,17 @@ struct ContentView: View { var fontDate: Font { switch viewMode { - case .month, - .week, - .single: - return .footnote - case .year(let yearDisplayMode): - switch yearDisplayMode { - case .compact: - return .system(size: 10, weight: .regular) - case .full: - return .footnote.weight(.semibold) - } + case .month, + .week, + .single: + return .footnote + case .year(let yearDisplayMode): + switch yearDisplayMode { + case .compact: + return .system(size: 10, weight: .regular) + case .full: + return .footnote.weight(.semibold) + } } }