diff --git a/CalendarX.xcodeproj/project.pbxproj b/CalendarX.xcodeproj/project.pbxproj index c8e910a..53cd206 100644 --- a/CalendarX.xcodeproj/project.pbxproj +++ b/CalendarX.xcodeproj/project.pbxproj @@ -24,6 +24,9 @@ 988A82E0279FEC9D000899B5 /* Theme.swift in Sources */ = {isa = PBXBuildFile; fileRef = 988A82DC279FEC9D000899B5 /* Theme.swift */; }; 988A82E1279FEC9D000899B5 /* AppInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 988A82DD279FEC9D000899B5 /* AppInfo.swift */; }; 988A82E3279FFB8A000899B5 /* Preference.swift in Sources */ = {isa = PBXBuildFile; fileRef = 988A82E2279FFB8A000899B5 /* Preference.swift */; }; + 98B5B6C929427A8A00114483 /* TitleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98B5B6C829427A8A00114483 /* TitleView.swift */; }; + 98B5B6CB294289F900114483 /* RecommendationsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98B5B6CA294289F900114483 /* RecommendationsView.swift */; }; + 98B5B6CD2942A6D800114483 /* apps.json in Resources */ = {isa = PBXBuildFile; fileRef = 98B5B6CC2942A6D800114483 /* apps.json */; }; 98BE991427A0E08500306061 /* Sparkle in Frameworks */ = {isa = PBXBuildFile; productRef = 98BE991327A0E08500306061 /* Sparkle */; }; 98BE991627A0F6AB00306061 /* RootView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98BE991527A0F6AB00306061 /* RootView.swift */; }; 98BE991827A0F75900306061 /* MainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98BE991727A0F75900306061 /* MainView.swift */; }; @@ -75,6 +78,9 @@ 988A82DC279FEC9D000899B5 /* Theme.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Theme.swift; sourceTree = ""; }; 988A82DD279FEC9D000899B5 /* AppInfo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppInfo.swift; sourceTree = ""; }; 988A82E2279FFB8A000899B5 /* Preference.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Preference.swift; sourceTree = ""; }; + 98B5B6C829427A8A00114483 /* TitleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TitleView.swift; sourceTree = ""; }; + 98B5B6CA294289F900114483 /* RecommendationsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecommendationsView.swift; sourceTree = ""; }; + 98B5B6CC2942A6D800114483 /* apps.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = apps.json; sourceTree = ""; }; 98BE991527A0F6AB00306061 /* RootView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RootView.swift; sourceTree = ""; }; 98BE991727A0F75900306061 /* MainView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainView.swift; sourceTree = ""; }; 98BE991B27A1397500306061 /* Calendar+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Calendar+.swift"; sourceTree = ""; }; @@ -177,6 +183,7 @@ children = ( 98BE991D27A1415F00306061 /* SettingsView.swift */, 98C9BD09290999F600F645AD /* MenuBarSettingsView.swift */, + 98B5B6CA294289F900114483 /* RecommendationsView.swift */, ); path = Settings; sourceTree = ""; @@ -184,6 +191,7 @@ 98CE8BDC27BBABF2009E5674 /* Resource */ = { isa = PBXGroup; children = ( + 98B5B6CC2942A6D800114483 /* apps.json */, 988530272818DB8A00FD98BC /* palette.json */, 98CE8BE327BDFA12009E5674 /* terms.json */, 98CE8BDA27BBAA93009E5674 /* tiaoxiu.json */, @@ -280,6 +288,7 @@ 98F4347627A24297009F18CC /* ScacleButton.swift */, 98ED365827A354CC00AF578A /* ScacleButtonPicker.swift */, 98CED54A27F3057100E0F758 /* RotationArrow.swift */, + 98B5B6C829427A8A00114483 /* TitleView.swift */, ); path = Component; sourceTree = ""; @@ -363,6 +372,7 @@ 98CED54E27F43CF100E0F758 /* InfoPlist.strings in Resources */, 98CE8BE827BF43EB009E5674 /* solarPF.json in Resources */, 98CE8BEE27BF5105009E5674 /* solarAF.json in Resources */, + 98B5B6CD2942A6D800114483 /* apps.json in Resources */, 982DABC027C32FC9002891A3 /* weekSF.json in Resources */, 98D573D627571EB6001C2D8C /* Assets.xcassets in Resources */, 98CE8BE027BDEF1D009E5674 /* chuxi.json in Resources */, @@ -407,6 +417,7 @@ 98BE991627A0F6AB00306061 /* RootView.swift in Sources */, 982DABC627C33343002891A3 /* Bundle+.swift in Sources */, 98F4347727A24297009F18CC /* ScacleButton.swift in Sources */, + 98B5B6C929427A8A00114483 /* TitleView.swift in Sources */, 98BE991E27A1415F00306061 /* SettingsView.swift in Sources */, 98C9BD0A290999F600F645AD /* MenuBarSettingsView.swift in Sources */, 982DABC427C332E1002891A3 /* Date+.swift in Sources */, @@ -431,6 +442,7 @@ 98FEAB9F27F6F0EA0034EC1F /* MenuBarStyle.swift in Sources */, 98D247962784324700F2B278 /* MenuBarPopover.swift in Sources */, 98F4347427A23ABE009F18CC /* MainViewModel.swift in Sources */, + 98B5B6CB294289F900114483 /* RecommendationsView.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/CalendarX/Assets.xcassets/GitHub.imageset/Contents.json b/CalendarX/Assets.xcassets/GitHub.imageset/Contents.json new file mode 100644 index 0000000..7d38a88 --- /dev/null +++ b/CalendarX/Assets.xcassets/GitHub.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "GitHub.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/CalendarX/Assets.xcassets/GitHub.imageset/GitHub.svg b/CalendarX/Assets.xcassets/GitHub.imageset/GitHub.svg new file mode 100644 index 0000000..aa05db9 --- /dev/null +++ b/CalendarX/Assets.xcassets/GitHub.imageset/GitHub.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/CalendarX/Assets.xcassets/Recommendations/Contents.json b/CalendarX/Assets.xcassets/Recommendations/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/CalendarX/Assets.xcassets/Recommendations/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/CalendarX/Assets.xcassets/Recommendations/HostsX.imageset/Contents.json b/CalendarX/Assets.xcassets/Recommendations/HostsX.imageset/Contents.json new file mode 100644 index 0000000..1ef8ba7 --- /dev/null +++ b/CalendarX/Assets.xcassets/Recommendations/HostsX.imageset/Contents.json @@ -0,0 +1,17 @@ +{ + "images" : [ + { + "idiom" : "mac", + "scale" : "1x" + }, + { + "filename" : "HostsX.png", + "idiom" : "mac", + "scale" : "2x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/CalendarX/Assets.xcassets/Recommendations/HostsX.imageset/HostsX.png b/CalendarX/Assets.xcassets/Recommendations/HostsX.imageset/HostsX.png new file mode 100644 index 0000000..28448c3 Binary files /dev/null and b/CalendarX/Assets.xcassets/Recommendations/HostsX.imageset/HostsX.png differ diff --git a/CalendarX/Assets.xcassets/Recommendations/OnlySwitch.imageset/Contents.json b/CalendarX/Assets.xcassets/Recommendations/OnlySwitch.imageset/Contents.json new file mode 100644 index 0000000..e055662 --- /dev/null +++ b/CalendarX/Assets.xcassets/Recommendations/OnlySwitch.imageset/Contents.json @@ -0,0 +1,17 @@ +{ + "images" : [ + { + "idiom" : "mac", + "scale" : "1x" + }, + { + "filename" : "OnlySwitch.png", + "idiom" : "mac", + "scale" : "2x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/CalendarX/Assets.xcassets/Recommendations/OnlySwitch.imageset/OnlySwitch.png b/CalendarX/Assets.xcassets/Recommendations/OnlySwitch.imageset/OnlySwitch.png new file mode 100644 index 0000000..1407be2 Binary files /dev/null and b/CalendarX/Assets.xcassets/Recommendations/OnlySwitch.imageset/OnlySwitch.png differ diff --git a/CalendarX/Component/ScacleButton.swift b/CalendarX/Component/ScacleButton.swift index 18325c3..67334af 100644 --- a/CalendarX/Component/ScacleButton.swift +++ b/CalendarX/Component/ScacleButton.swift @@ -10,7 +10,7 @@ import SwiftUI struct ScacleButton: View { let action: VoidClosure - + @ViewBuilder let label: () -> Label @@ -46,18 +46,15 @@ struct ScacleCapsuleButton: View { foregroundColor: Color, backgroundColor: Color, action: VoidClosure - + var body: some View { ScacleButton(action: action) { - HStack { - Spacer() - Text(title) - Spacer() - } - .padding(.vertical, 5) - .foregroundColor(foregroundColor) - .background(backgroundColor) - .clipShape(Capsule()) + Text(title) + .frame(maxWidth: .infinity) + .padding(.vertical, 5) + .foregroundColor(foregroundColor) + .background(backgroundColor) + .clipShape(Capsule()) } } } diff --git a/CalendarX/Component/TitleView.swift b/CalendarX/Component/TitleView.swift new file mode 100644 index 0000000..b66adf2 --- /dev/null +++ b/CalendarX/Component/TitleView.swift @@ -0,0 +1,26 @@ +// +// TitleView.swift +// CalendarX +// +// Created by zm on 2022/12/9. +// + +import SwiftUI + +struct TitleView: View { + + let title: () -> Title + + @ViewBuilder + let actions: () -> Content + + var body: some View { + ZStack { + title().font(.title2) + HStack(content: actions) + .frame(maxWidth: .infinity, alignment: .trailing) + } + } +} + + diff --git a/CalendarX/Constant.swift b/CalendarX/Constant.swift index a3396a2..eb36ec7 100644 --- a/CalendarX/Constant.swift +++ b/CalendarX/Constant.swift @@ -52,12 +52,13 @@ extension Image { static let success = Image(systemName: "checkmark.circle.fill") static let download = Image(systemName: "arrow.down") static let close = Image(systemName: "xmark") - static let appLogo = Image("AppLogo", bundle: .main) static let leftArrow = Image(systemName: "chevron.left") static let rightArrow = Image(systemName: "chevron.right") static let circle = Image(systemName: "circle") static let link = Image(systemName: "link") - static let calendar = Image(nsImage: .menubarIcon!) + static let recommend = Image(systemName: "hand.thumbsup.fill") + static let gitHub = Image("GitHub").renderingMode(.template).resizable() + static let menubarIcon = Image("MenubarIcon").renderingMode(.template).resizable() } diff --git a/CalendarX/Extension/View+.swift b/CalendarX/Extension/View+.swift index 0d68b52..987a4eb 100644 --- a/CalendarX/Extension/View+.swift +++ b/CalendarX/Extension/View+.swift @@ -129,10 +129,20 @@ extension View { modifier(ColorSchemeModifier(colorScheme: colorScheme)) } + + func fullScreenCover(_ backgroudColor: Color = .background) -> some View { + background(backgroudColor) + .transition(.move(edge: .bottom)) + .zIndex(1) + } + + var hoverEffect: some View { modifier(HoverModifier()) } + + } diff --git a/CalendarX/Module/Calender/DateView.swift b/CalendarX/Module/Calender/DateView.swift index f72c0d7..c19922a 100644 --- a/CalendarX/Module/Calender/DateView.swift +++ b/CalendarX/Module/Calender/DateView.swift @@ -10,34 +10,21 @@ import WrappingHStack struct DateView: View { - @Binding - var isShown: Bool - let day: XDay var body: some View { VStack(spacing: 10) { - titleView() + TitleView { + Text(day.date, style: .date) + } actions: { + ScacleImageButton(image: .close, action: Router.backMain) + } + Text(day.lunarDate).font(.footnote).foregroundColor(.secondary) FestivalsView(festivals: day.festivals) SchedulesView(events: day.events) } } - - @ViewBuilder - func titleView() -> some View { - HStack { - ScacleImageButton(image: .close, action: {}).hidden() - Spacer() - Text(day.date, style: .date).font(.title2) - Spacer() - ScacleImageButton(image: .close) { - withAnimation { isShown.toggle() } - } - } - - Text(day.lunarDate).font(.footnote).foregroundColor(.secondary) - } - + } @@ -134,11 +121,9 @@ struct SchedulesView: View { struct GroupEmptyRow: View { let title: LocalizedStringKey var body: some View { - HStack { - Text(title) - Spacer() - } - .foregroundColor(.secondary) + Text(title) + .frame(maxWidth: .infinity, alignment: .leading) + .foregroundColor(.secondary) } } diff --git a/CalendarX/Module/Calender/MainView.swift b/CalendarX/Module/Calender/MainView.swift index 55cb73f..a2c5979 100644 --- a/CalendarX/Module/Calender/MainView.swift +++ b/CalendarX/Module/Calender/MainView.swift @@ -9,73 +9,60 @@ import SwiftUI struct MainView: View { - + private let weekday = Preference.shared.weekday - + private let showSchedule = Preference.shared.showSchedule - + @StateObject private var viewModel = MainViewModel() - @State - private var isShown = false - - @State - private var selectedDay: XDay! + @Binding + var date: Date var body: some View { - - ZStack { - if isShown { - DateView(isShown: $isShown, day: selectedDay).height(.mainHeight).transition(.move(edge: .bottom)) - } - CalendarView(date: viewModel.date, - firstWeekday: weekday, - timestamp: viewModel.timestamp, - header: header, - weekView: weekView, - dayView: dayView) - .equatable() - .opacity(isShown ? 0:1) - .height(.mainHeight) - - } - + + CalendarView(date: date, + firstWeekday: weekday, + timestamp: viewModel.timestamp, + header: header, + weekView: weekView, + dayView: dayView) + .equatable() + .height(.mainHeight) + } - + private func header() -> some View { - + HStack { - MonthYearPicker(date: $viewModel.date) + MonthYearPicker(date: $date) Spacer() - ScacleImageButton(image: .leftArrow, action: viewModel.lastMonth).width(.buttonWidth) - ScacleImageButton(image: .circle, action: viewModel.today).width(.buttonWidth) - ScacleImageButton(image: .rightArrow, action: viewModel.nextMonth).width(.buttonWidth) + ScacleImageButton(image: .leftArrow, action: { date.lastMonth() }).width(.buttonWidth) + ScacleImageButton(image: .circle, action: { date = Date() }).width(.buttonWidth) + ScacleImageButton(image: .rightArrow, action: { date.nextMonth() }).width(.buttonWidth) } - - + + } - + private func weekView(date: Date) -> some View { Text(L10n.shortWeekday(from: date)) .foregroundColor(date.inWeekend ? .secondary : .primary) .square(30) } - + private func dayView(inSameMonth: Bool, day: XDay) -> some View { ScacleButton { - withAnimation() { - isShown.toggle() - selectedDay = day - } + Router.toDate(day) } label: { ZStack { - + if day.inToday { RoundedRectangle(cornerRadius: 4) .stroke(Color.accentColor, lineWidth: 1) } - + if day.inWorking { Color.workdayBackground.cornerRadius(4) Text(day.stateDesc) @@ -88,14 +75,14 @@ struct MainView: View { .font(.system(size: 6)).offset(x: -14, y: -14) .foregroundColor(.accentColor) } - + if day.events.isNotEmpty, showSchedule { Circle() - .size(width: 5, height: 5) + .square(5) .foregroundColor(.accentColor) .offset(x: 32, y: 3) } - + VStack { Text(day.title) .font(.title3) @@ -104,12 +91,12 @@ struct MainView: View { .font(.caption2) .foregroundColor(.secondary) } - + } } .opacity(inSameMonth ? 1:0.3) .square(40) - + } } @@ -117,20 +104,20 @@ struct MonthYearPicker: View { @Binding var date: Date - + private let pref = Preference.shared - + @State private var isPresentedOfMonth = false - + @State private var isPresentedOfYear = false - - + + var body: some View { - + let colorScheme = pref.colorScheme, tint = pref.color - + ScacleButtonPicker(items: Array(Solar.minMonth...Solar.maxMonth), tint: tint, colorScheme: colorScheme, @@ -140,7 +127,7 @@ struct MonthYearPicker: View { } itemLabel: { Text(L10n.monthSymbol(from: $0)) } - + ScacleButtonPicker(items: Array(Solar.minYear...Solar.maxYear), tint: tint, colorScheme: colorScheme, @@ -150,16 +137,16 @@ struct MonthYearPicker: View { } itemLabel: { Text(String($0)) } - + } } struct CalendarView: View { - + private let date: Date, firstWeekday: XWeekday, timestamp: TimeInterval - + private let dayView: (Bool, XDay) -> Day, header: () -> Header, weekView: (Date) -> Week - + init(date: Date, firstWeekday: XWeekday, timestamp: TimeInterval, @@ -174,14 +161,14 @@ struct CalendarView: View { self.header = header self.weekView = weekView } - + private let columns = Array(repeating: GridItem(), count: Solar.daysInWeek) - + var body: some View { let days = makeDays() let spacing: CGFloat? = days.count > Solar.minDates ? 1.7: nil - + LazyVGrid(columns: columns, spacing: spacing) { Section(content: { ForEach(0..: View { } }, header: header) } - + } - + private func makeDays() -> [XDay] { var calendar = Calendar.gregorian calendar.firstWeekday = firstWeekday.rawValue let dates = calendar.generateDates(for: date) let events = Event.fetchEvents(with: dates.first!, end: dates.last!) - + return dates.map { date in XDay(date, events: events.filter{$0.startDate.isSameDay(as: date)}) } diff --git a/CalendarX/Module/Calender/RootView.swift b/CalendarX/Module/Calender/RootView.swift index 14ec9d0..c53a01f 100644 --- a/CalendarX/Module/Calender/RootView.swift +++ b/CalendarX/Module/Calender/RootView.swift @@ -7,7 +7,6 @@ import SwiftUI - struct RootView: View { @StateObject @@ -15,7 +14,10 @@ struct RootView: View { @StateObject private var router = Router.shared - + + @State + private var date = Date() + var body: some View { ZStack { @@ -32,8 +34,11 @@ struct RootView: View { @ViewBuilder private var content: some View { switch router.path { - case .main: MainView() + case .main: MainView(date: $date) case .settings: SettingsView() + case .date(let day): DateView(day: day).fullScreenCover() + case .recommendations: RecommendationsView().fullScreenCover() + case .menuBarSettings: MenuBarSettingsView().fullScreenCover() } } diff --git a/CalendarX/Module/Settings/MenuBarSettingsView.swift b/CalendarX/Module/Settings/MenuBarSettingsView.swift index de49725..e48eba8 100644 --- a/CalendarX/Module/Settings/MenuBarSettingsView.swift +++ b/CalendarX/Module/Settings/MenuBarSettingsView.swift @@ -8,13 +8,8 @@ import SwiftUI import Combine - - struct MenuBarSettingsView: View { - @Binding - var isShown: Bool - @EnvironmentObject private var pref: Preference @@ -43,8 +38,11 @@ struct MenuBarSettingsView: View { var body: some View { VStack(spacing: 10) { - titleView() - + TitleView { + Text(L10n.Settings.menuBarStyle) + } actions: { + ScacleImageButton(image: .close, action: Router.backSettings) + } Picker(selection: $style) { ForEach(MenuBarStyle.allCases, id: \.self) { @@ -64,41 +62,25 @@ struct MenuBarSettingsView: View { } } .frame(maxHeight: .infinity) - - - ScacleCapsuleButton(title: L10n.MenubarStyle.save, foregroundColor: .white, backgroundColor: disabled ? .secondary: .accentColor) { - withAnimation { isShown.toggle() } - save() - } + + + ScacleCapsuleButton(title: L10n.MenubarStyle.save, + foregroundColor: .white, + backgroundColor: disabled ? .secondary: .accentColor, + action: save) .frame(width: .mainWidth/2) .disabled(disabled) .onChange(of: saved, notification: .titleStyleDidChanged) - + } .focusable(false) } - func titleView() -> some View { - HStack { - ScacleImageButton(image: .close, action: {}).hidden() - Spacer() - Text(L10n.Settings.menuBarStyle).font(.title2) - Spacer() - ScacleImageButton(image: .close) { - withAnimation { isShown.toggle() } - } - } - } - - @ViewBuilder func defaultContent() -> some View { - Image.calendar - .renderingMode(.template) - .resizable() - .frame(width: 30, height: 30) + Image.menubarIcon.square(30) Text(Date().day.description) .font(.title3) @@ -119,32 +101,31 @@ struct MenuBarSettingsView: View { pref.menuBarStyle = style saved.toggle() + + Router.backSettings() } - } struct TextView: View { - @Binding var text: String - var body: some View { VStack { Text(text).font(.title3) - + TextField(AppInfo.name, text: $text) .textFieldStyle(.plain) - .padding(3) - .background(Capsule().stroke(Color.secondary)) .multilineTextAlignment(.center) .onReceive(Just(text)) { _ in text.limit() } + + Divider().padding(.horizontal) Text(L10n.MenubarStyle.tips) .font(.footnote) @@ -156,11 +137,9 @@ struct TextView: View { struct DateFormatView: View { - @Binding var dateFormat: String - var body: some View { VStack { @@ -168,12 +147,12 @@ struct DateFormatView: View { TextField(AppInfo.dateFormat, text: $dateFormat) .textFieldStyle(.plain) - .padding(3) - .background(Capsule().stroke(Color.secondary)) .multilineTextAlignment(.center) .onReceive(Just(dateFormat)) { _ in dateFormat.limit() } + + Divider().padding(.horizontal) Text(L10n.MenubarStyle.tips) .font(.footnote) diff --git a/CalendarX/Module/Settings/RecommendationsView.swift b/CalendarX/Module/Settings/RecommendationsView.swift new file mode 100644 index 0000000..2b09cda --- /dev/null +++ b/CalendarX/Module/Settings/RecommendationsView.swift @@ -0,0 +1,64 @@ +// +// RecommendationsView.swift +// CalendarX +// +// Created by zm on 2022/12/9. +// + +import SwiftUI + +struct RecommendationsView: View { + + private let apps: [XApp] = Bundle.main.json2Object(from: "apps") ?? [] + + var body: some View { + + VStack { + + TitleView { + Text(L10n.Settings.recommendations) + } actions: { + ScacleImageButton(image: .close, action: Router.backSettings) + } + + ScrollView { + + ForEach(apps) { app in + AppView(app: app) + } + + } + + } + + } +} + +struct AppView: View { + + let app: XApp + + var body: some View { + HStack { + Image(app.name).resizable().square(60) + VStack(alignment: .leading, spacing: 5) { + HStack { + Text(app.name) + ScacleButton { + NSWorkspace.open(app.link) + } label: { + Image.gitHub.square(15) + } + } + Text(app.about).font(.footnote).foregroundColor(.secondary).lineLimit(2) + } + } + .frame(maxWidth: .infinity, alignment: .leading) + + } +} + +struct XApp: Decodable, Identifiable { + var id: String { name } + let name: String, about: String, link: String +} diff --git a/CalendarX/Module/Settings/SettingsView.swift b/CalendarX/Module/Settings/SettingsView.swift index 3569ea4..f34f156 100644 --- a/CalendarX/Module/Settings/SettingsView.swift +++ b/CalendarX/Module/Settings/SettingsView.swift @@ -10,71 +10,44 @@ import LaunchAtLogin struct SettingsView: View { - - - @State - private var isShown = false - var body: some View { - - ZStack { - if isShown { - MenuBarSettingsView(isShown: $isShown) - .transition(.move(edge: .bottom)) - } - settingsView() - .opacity(isShown ? 0:1) - } - - - } - - func settingsView() -> some View { - + VStack(spacing: 10) { - - titleView() - + + TitleView { Text( L10n.Settings.title) } actions: {} + Section { ThemeRow() TintRow() WeekdayRow() - MenuBarStyleRow(isShown: $isShown) + MenuBarStyleRow() ScheduleRow() LaunchRow() + RecommendationsRow() }.padding(.bottom, 3) - + Section { LastRow() } - + } + .height(.mainHeight) + + } - func titleView() -> some View { - HStack { - Image.link.hidden() - Spacer() - Text(L10n.Settings.title).font(.title2) - Spacer() - ScacleImageButton(image: .link) { - NSWorkspace.open(XLink.gitHub) - } - } - } - } struct ThemeRow: View { - + @EnvironmentObject private var pref: Preference - + var body: some View { - - + + SettingsPickerRow(title: L10n.Settings.theme, items: Theme.allCases, selection: pref.$theme) { Text($0.title) } @@ -82,18 +55,18 @@ struct ThemeRow: View { // items: Language.allCases, // selection: pref.$language) { Text($0.rawValue) } } - + } struct TintRow: View { - + @EnvironmentObject private var pref: Preference - - + + var body: some View { - + SettingsPickerRow(title: L10n.Settings.tint, items: Tint.allCases, isGrid: true, @@ -101,14 +74,14 @@ struct TintRow: View { Circle().square(15).foregroundColor(Tint[$0]) } } - + } struct WeekdayRow: View{ - + @EnvironmentObject private var pref: Preference - + var body: some View { SettingsPickerRow(title: L10n.Settings.startWeekOn, items: XWeekday.allCases, @@ -117,53 +90,47 @@ struct WeekdayRow: View{ } struct MenuBarStyleRow: View { - - - @Binding - var isShown: Bool - + @EnvironmentObject private var pref: Preference + + var body: some View { + SettingsCommonRow(title: L10n.Settings.menuBarStyle, + detail: pref.menuBarStyle.title, + action: Router.toMenuBarSettings) + } + +} +struct RecommendationsRow: View { var body: some View { - HStack { - Text(L10n.Settings.menuBarStyle).font(.title3) - Spacer() - ScacleButton { - withAnimation() { - isShown.toggle() - } - } label: { - HStack { - Text(pref.menuBarStyle.title) - Image.rightArrow - }.foregroundColor(.secondary) - } - } + SettingsCommonRow(title: L10n.Settings.recommendations, detail: .none, + action: Router.toRecommendations) } + } struct ScheduleRow: View { - + @EnvironmentObject private var pref: Preference - + @State private var isAuthorized = Event.isAuthorized - + var body: some View { - + let showSchedule = Binding { isAuthorized ? pref.showSchedule : false } set: { requestAccessToEvent() pref.showSchedule = $0 } - + Toggle(isOn: showSchedule) { Text(L10n.Settings.showSchedule).font(.title3) } .checkboxStyle() - + } func requestAccessToEvent() { @@ -175,7 +142,7 @@ struct ScheduleRow: View { } } } - + } struct LaunchRow: View { @@ -186,43 +153,80 @@ struct LaunchRow: View { } struct LastRow: View { - - + + var body: some View { HStack(spacing: 10) { - + ScacleCapsuleButton(title: L10n.Settings.quitApp, foregroundColor: .white, backgroundColor: .secondary) { NSApp.terminate(.none) } - + ScacleCapsuleButton(title: L10n.Settings.checkForUpdates, foregroundColor: .white, backgroundColor: .accentColor, action: Updater.checkForUpdates) - + } + + + HStack { + Text("\(AppInfo.version) ( \(AppInfo.commitHash) )") + .font(.footnote) + .foregroundColor(.secondary) + + ScacleButton { + NSWorkspace.open(XLink.gitHub) + } label: { + Image.gitHub.square(11) + } + } + + + } +} - Text("\(AppInfo.version) ( \(AppInfo.commitHash) )") - .font(.footnote) + +struct SettingsCommonRow: View { + + let title: LocalizedStringKey, detail: LocalizedStringKey?, action: VoidClosure + + var body: some View { + + HStack { + Text(title).font(.title3) + Spacer() + + Group { + if let detail = detail { + Text(detail) + } + Image.rightArrow + } .foregroundColor(.secondary) + + } + .contentShape(Rectangle()) + .onTapGesture(perform: action) + } } struct SettingsPickerRow: View { - + let title: LocalizedStringKey - + let items: [Item] - + let isGrid: Bool - + @Binding var selection: Item - + @ViewBuilder let itemLabel: (Item) -> Label - + @State private var isPresented = false - + @EnvironmentObject private var pref: Preference - + init(title: LocalizedStringKey, items: [Item], isGrid: Bool = false, @@ -234,9 +238,9 @@ struct SettingsPickerRow: View { self._selection = selection self.itemLabel = itemLabel } - + var body: some View { - + HStack { Text(title).font(.title3) Spacer() diff --git a/CalendarX/Resource/apps.json b/CalendarX/Resource/apps.json new file mode 100644 index 0000000..e9a374a --- /dev/null +++ b/CalendarX/Resource/apps.json @@ -0,0 +1,12 @@ +[ + { + "name": "OnlySwitch", + "about": "⚙️ All-in-One menu bar app, hide 💻MacBook Pro's notch, dark mode, AirPods, Shortcuts", + "link": "https://github.com/jacklandrin/OnlySwitch" + }, + { + "name": "HostsX", + "about": "A lightweight macOS app for updating local hosts", + "link": "https://github.com/ZzzM/HostsX" + } +] \ No newline at end of file diff --git a/CalendarX/Resource/tiaoxiu.json b/CalendarX/Resource/tiaoxiu.json index 725b2a0..86fe28a 100644 --- a/CalendarX/Resource/tiaoxiu.json +++ b/CalendarX/Resource/tiaoxiu.json @@ -365,6 +365,42 @@ "1006": 2, "1007": 2, "1008": 1, - "1009": 1 + "1009": 1, + "1231": 2 + }, + "2023": { + "0101": 2, + "0102": 2, + "0121": 2, + "0122": 2, + "0123": 2, + "0124": 2, + "0125": 2, + "0126": 2, + "0127": 2, + "0128": 1, + "0129": 1, + "0405": 2, + "0423": 1, + "0429": 2, + "0430": 2, + "0501": 2, + "0502": 2, + "0503": 2, + "0506": 1, + "0622": 2, + "0623": 2, + "0624": 2, + "0625": 1, + "0929": 2, + "0930": 2, + "1001": 2, + "1002": 2, + "1003": 2, + "1004": 2, + "1005": 2, + "1006": 2, + "1007": 1, + "1008": 1 } } diff --git a/CalendarX/Service/L10n.swift b/CalendarX/Service/L10n.swift index 4f06c57..456584e 100644 --- a/CalendarX/Service/L10n.swift +++ b/CalendarX/Service/L10n.swift @@ -19,6 +19,7 @@ struct L10n { enum Settings { static let title = "settings.title".l10nKey + static let recommendations = "settings.recommendations".l10nKey static let menuBarStyle = "settings.menuBarStyle".l10nKey static let theme = "settings.theme".l10nKey static let tint = "settings.tint".l10nKey diff --git a/CalendarX/ViewModel/MainViewModel.swift b/CalendarX/ViewModel/MainViewModel.swift index 521e4bb..99d945a 100644 --- a/CalendarX/ViewModel/MainViewModel.swift +++ b/CalendarX/ViewModel/MainViewModel.swift @@ -9,15 +9,10 @@ import SwiftUI class MainViewModel: ObservableObject { - - @Published - var date: Date - @Published var timestamp: TimeInterval init() { - date = Date() timestamp = Date().timeIntervalSince1970 NotificationCenter.default .publisher(for: .EKEventStoreChanged) @@ -29,10 +24,4 @@ class MainViewModel: ObservableObject { .assign(to: &$timestamp) } - func nextMonth() { date.nextMonth() } - - func lastMonth() { date.lastMonth() } - - func today() { date = Date() } - } diff --git a/CalendarX/ViewModel/Router.swift b/CalendarX/ViewModel/Router.swift index 094cdc1..7db6e65 100644 --- a/CalendarX/ViewModel/Router.swift +++ b/CalendarX/ViewModel/Router.swift @@ -18,20 +18,57 @@ class Router: ObservableObject { static let shared = Router() enum Path { - case main, settings + case main, date(XDay), settings, recommendations, menuBarSettings } @Published var path = Path.main - + private func to(_ path: Path) { self.path = path } +} + +extension Router { + + static func toMain() { + shared.to(.main) + } + + static func backMain() { + withAnimation { + toMain() + } + } + + static func toDate(_ day: XDay) { + withAnimation { + shared.to(.date(day)) + } + } +} + +extension Router { static func toSettings() { shared.to(.settings) } - static func toMain() { - shared.to(.main) + + static func backSettings() { + withAnimation { + toSettings() + } + } + + static func toRecommendations() { + withAnimation { + shared.to(.recommendations) + } + } + + static func toMenuBarSettings() { + withAnimation { + shared.to(.menuBarSettings) + } } } diff --git a/CalendarX/en.lproj/Localizable.strings b/CalendarX/en.lproj/Localizable.strings index 5ebd2fd..0b804eb 100644 --- a/CalendarX/en.lproj/Localizable.strings +++ b/CalendarX/en.lproj/Localizable.strings @@ -6,6 +6,7 @@ */ "settings.title" = "Settings"; +"settings.recommendations" = "App Recommendations"; "settings.menuBarStyle" = "Menubar Style"; "settings.theme" = "Theme"; "settings.tint" = "Tint"; diff --git a/CalendarX/zh-Hans.lproj/Localizable.strings b/CalendarX/zh-Hans.lproj/Localizable.strings index d675381..becb004 100644 --- a/CalendarX/zh-Hans.lproj/Localizable.strings +++ b/CalendarX/zh-Hans.lproj/Localizable.strings @@ -6,6 +6,7 @@ */ "settings.title" = "设置"; +"settings.recommendations" = "App 推荐"; "settings.menuBarStyle" = "菜单栏样式"; "settings.theme" = "主题"; "settings.tint" = "色调"; diff --git a/README.md b/README.md index ddc469f..61b6628 100644 --- a/README.md +++ b/README.md @@ -28,21 +28,19 @@ A lightweight macOS app for displaying calendar and time ## Snapshots - Calendar - left click to show - + - + - Settings - right click to show - + -- Menubar - custom styles (default, text, date & time) + + - - - ## Dependencies - [Sparkle](https://github.com/sparkle-project/Sparkle) - [WrappingHStack](https://github.com/dkk/WrappingHStack) - [LaunchAtLogin](https://github.com/sindresorhus/LaunchAtLogin) -- [Schedule](https://github.com/luoxiu/Schedule) +- [Schedule](https://github.com/luoxiu/Schedule) diff --git a/assets/md01.png b/assets/cd01.png similarity index 100% rename from assets/md01.png rename to assets/cd01.png diff --git a/assets/md03.png b/assets/cd02.png similarity index 100% rename from assets/md03.png rename to assets/cd02.png diff --git a/assets/ml01.png b/assets/cl01.png similarity index 100% rename from assets/ml01.png rename to assets/cl01.png diff --git a/assets/ml03.png b/assets/cl02.png similarity index 100% rename from assets/ml03.png rename to assets/cl02.png diff --git a/assets/md02.png b/assets/md02.png deleted file mode 100644 index 7350680..0000000 Binary files a/assets/md02.png and /dev/null differ diff --git a/assets/ml02.png b/assets/ml02.png deleted file mode 100644 index 7078d7b..0000000 Binary files a/assets/ml02.png and /dev/null differ diff --git a/assets/s01.png b/assets/s01.png deleted file mode 100644 index a3ec2e9..0000000 Binary files a/assets/s01.png and /dev/null differ diff --git a/assets/s02.png b/assets/s02.png deleted file mode 100644 index 958bb40..0000000 Binary files a/assets/s02.png and /dev/null differ diff --git a/assets/s03.png b/assets/s03.png deleted file mode 100644 index f707d4a..0000000 Binary files a/assets/s03.png and /dev/null differ diff --git a/assets/sd01.png b/assets/sd01.png new file mode 100644 index 0000000..7e9fd16 Binary files /dev/null and b/assets/sd01.png differ diff --git a/assets/sd02.png b/assets/sd02.png new file mode 100644 index 0000000..be4e645 Binary files /dev/null and b/assets/sd02.png differ diff --git a/assets/sd03.png b/assets/sd03.png new file mode 100644 index 0000000..15243fc Binary files /dev/null and b/assets/sd03.png differ diff --git a/assets/sl01.png b/assets/sl01.png new file mode 100644 index 0000000..65772ae Binary files /dev/null and b/assets/sl01.png differ diff --git a/assets/sl02.png b/assets/sl02.png new file mode 100644 index 0000000..069978d Binary files /dev/null and b/assets/sl02.png differ diff --git a/assets/sl03.png b/assets/sl03.png new file mode 100644 index 0000000..b42adc8 Binary files /dev/null and b/assets/sl03.png differ diff --git a/changelogs/CHANGELOG.md b/changelogs/CHANGELOG.md index 1925874..545f744 100644 --- a/changelogs/CHANGELOG.md +++ b/changelogs/CHANGELOG.md @@ -1,3 +1,16 @@ +## 2.2.2 - 2022-12-09 + +### Added +- Chinese statutory holidays in 2023 +- App Recommendations + +### Changed + +- Settings UI +- Transition animation + +--- + ## 2.2.1 - 2022-11-03 ### Added @@ -16,7 +29,7 @@ ### Added - Enable launch at login - + ### Changed - New design - Updated App name to **CalenderX** diff --git a/changelogs/CHANGELOG_SC.md b/changelogs/CHANGELOG_SC.md index 95c1fbb..338abfe 100644 --- a/changelogs/CHANGELOG_SC.md +++ b/changelogs/CHANGELOG_SC.md @@ -1,3 +1,17 @@ +## 2.2.2 - 2022-12-09 + +### Added +- 2023 年中国法定节假日 +- App 推荐 + +### Changed + +- 设置界面 + +- 过渡动画 + +--- + ## 2.2.1 - 2022-11-03 ### Added