diff --git a/JShift.xcodeproj/project.pbxproj b/JShift.xcodeproj/project.pbxproj index bf160e4..9193b17 100644 --- a/JShift.xcodeproj/project.pbxproj +++ b/JShift.xcodeproj/project.pbxproj @@ -234,7 +234,7 @@ attributes = { BuildIndependentTargetsInParallel = 1; LastSwiftUpdateCheck = 1600; - LastUpgradeCheck = 1600; + LastUpgradeCheck = 2600; TargetAttributes = { 5436B6092CE8DEEC00E8CBFA = { CreatedOnToolsVersion = 16.0; @@ -375,9 +375,10 @@ CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_ASSET_PATHS = "\"JShift/Preview Content\""; - DEVELOPMENT_TEAM = 8KH9QD5V23; + ENABLE_APP_SANDBOX = YES; ENABLE_PREVIEWS = YES; ENABLE_USER_SCRIPT_SANDBOXING = NO; + ENABLE_USER_SELECTED_FILES = readonly; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = JShift/Info.plist; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.finance"; @@ -391,7 +392,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.6; + MARKETING_VERSION = 1.1.7; PRODUCT_BUNDLE_IDENTIFIER = com.ShinKawakami.JShift.JShift; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = YES; @@ -409,9 +410,10 @@ CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_ASSET_PATHS = "\"JShift/Preview Content\""; - DEVELOPMENT_TEAM = 8KH9QD5V23; + ENABLE_APP_SANDBOX = YES; ENABLE_PREVIEWS = YES; ENABLE_USER_SCRIPT_SANDBOXING = NO; + ENABLE_USER_SELECTED_FILES = readonly; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = JShift/Info.plist; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.finance"; @@ -425,7 +427,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.6; + MARKETING_VERSION = 1.1.7; PRODUCT_BUNDLE_IDENTIFIER = com.ShinKawakami.JShift.JShift; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = YES; @@ -469,6 +471,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = dwarf; + DEVELOPMENT_TEAM = 8KH9QD5V23; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; ENABLE_USER_SCRIPT_SANDBOXING = YES; @@ -493,6 +496,7 @@ MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; + STRING_CATALOG_GENERATE_SYMBOLS = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; }; @@ -533,6 +537,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEVELOPMENT_TEAM = 8KH9QD5V23; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_USER_SCRIPT_SANDBOXING = YES; @@ -550,6 +555,7 @@ MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; SDKROOT = iphoneos; + STRING_CATALOG_GENERATE_SYMBOLS = YES; SWIFT_COMPILATION_MODE = wholemodule; VALIDATE_PRODUCT = YES; }; @@ -561,7 +567,6 @@ BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = 8KH9QD5V23; GENERATE_INFOPLIST_FILE = YES; IPHONEOS_DEPLOYMENT_TARGET = 18.0; MARKETING_VERSION = 1.0; @@ -580,7 +585,6 @@ BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = 8KH9QD5V23; GENERATE_INFOPLIST_FILE = YES; IPHONEOS_DEPLOYMENT_TARGET = 18.0; MARKETING_VERSION = 1.0; @@ -598,7 +602,6 @@ buildSettings = { CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = 8KH9QD5V23; GENERATE_INFOPLIST_FILE = YES; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = com.ShinKawakami.JShift.JShiftUITests; @@ -615,7 +618,6 @@ buildSettings = { CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = 8KH9QD5V23; GENERATE_INFOPLIST_FILE = YES; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = com.ShinKawakami.JShift.JShiftUITests; diff --git a/JShift.xcodeproj/project.xcworkspace/xcuserdata/shin.xcuserdatad/UserInterfaceState.xcuserstate b/JShift.xcodeproj/project.xcworkspace/xcuserdata/shin.xcuserdatad/UserInterfaceState.xcuserstate index 4be52c3..0cac6a4 100644 Binary files a/JShift.xcodeproj/project.xcworkspace/xcuserdata/shin.xcuserdatad/UserInterfaceState.xcuserstate and b/JShift.xcodeproj/project.xcworkspace/xcuserdata/shin.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/JShift/JShift.entitlements b/JShift/JShift.entitlements index 87ac9f4..001264d 100644 --- a/JShift/JShift.entitlements +++ b/JShift/JShift.entitlements @@ -12,9 +12,5 @@ CloudKit - com.apple.security.app-sandbox - - com.apple.security.files.user-selected.read-only - diff --git a/JShift/Models/CalendarManager.swift b/JShift/Models/CalendarManager.swift index 4296e0a..3ba180b 100644 --- a/JShift/Models/CalendarManager.swift +++ b/JShift/Models/CalendarManager.swift @@ -23,6 +23,7 @@ final class CalendarManager { private func syncCalendarList() async { let fetchCalendarsQuery = GTLRCalendarQuery_CalendarListList.query() + fetchCalendarsQuery.maxResults = 250 await withCheckedContinuation { continuation in service.executeQuery(fetchCalendarsQuery) { ticket, response, error in if let error { @@ -43,6 +44,7 @@ final class CalendarManager { let fetchEventsQuery = GTLRCalendarQuery_EventsList.query(withCalendarId: calendarId) fetchEventsQuery.singleEvents = true fetchEventsQuery.syncToken = syncToken + fetchEventsQuery.maxResults = 1500 await withCheckedContinuation { continuation in service.executeQuery(fetchEventsQuery) { ticket, response, error in diff --git a/JShift/Models/SwiftData/JobSchemaV1.swift b/JShift/Models/SwiftData/JobSchemaV1.swift index dd4cf3d..e3c5ce2 100644 --- a/JShift/Models/SwiftData/JobSchemaV1.swift +++ b/JShift/Models/SwiftData/JobSchemaV1.swift @@ -9,7 +9,7 @@ enum JobSchemaV1: VersionedSchema { @Model final class Job { - let id: UUID = UUID() + var id: UUID = UUID() var name: String = "" var color: JobColor = JobColor.red var salaryType: JobSalaryType = JobSalaryType.hourly @@ -57,7 +57,7 @@ enum JobSchemaV1: VersionedSchema { @Model final class OneTimeJob { - let id: UUID = UUID() + var id: UUID = UUID() var name: String = "" var date: Date = Date() var salary: Int = 0 diff --git a/JShift/Views/ContentView.swift b/JShift/Views/ContentView.swift index 0763ce8..8264bb1 100644 --- a/JShift/Views/ContentView.swift +++ b/JShift/Views/ContentView.swift @@ -4,7 +4,7 @@ struct ContentView: View { @State private var selectedTab: Tab = .shift @State private var isWelcomePresented = false @Environment(\.openURL) private var openURL - private let AVAIABLE_OB_VERSION = "4" + private let AVAIABLE_OB_VERSION = "5" var body: some View { TabView(selection: $selectedTab) { @@ -39,13 +39,12 @@ struct ContentView: View { title: "アップデート内容", detailText: "", bulletedListItems: [ - .init(title: "チャート", description: "年間給与のチャートを復活させました。", symbolName: "chart.bar.xaxis.ascending", tintColor: UIColor(.green)), - .init(title: "給与表示", description: "給与の表示順を給与の高い順に変更しました。", symbolName: "arrow.up.arrow.down", tintColor: UIColor(.blue)), + .init(title: "iOS 26に対応", description: "iOS 26対応と軽微な不具合の修正", symbolName: "apple.logo", tintColor: UIColor(.green)), ], boldButtonItem: .init(title: "続ける", action: { isWelcomePresented = false }), - linkButtonItem: .init(title: "詳細", action: { openURL(URL(string: "https://github.com/shinking02/JShift/commit/2bb25dfe5a226385cea768bd6562368fe5018ade")!) }) + linkButtonItem: .init(title: "詳細", action: { openURL(URL(string: "https://github.com/shinking02/JShift/pull/12")!) }) ) } ) diff --git a/JShift/Views/Salary/SalaryContentView.swift b/JShift/Views/Salary/SalaryContentView.swift index 8c1aee9..95256d6 100644 --- a/JShift/Views/Salary/SalaryContentView.swift +++ b/JShift/Views/Salary/SalaryContentView.swift @@ -60,7 +60,7 @@ struct SalaryContentView: View { .cornerRadius(3) .foregroundStyle(Color.secondary) } - .animation(.none) + .animation(nil, value: salaryData) .frame(height: 260) .listRowBackground(Color.clear) .chartBackground { chartProxy in @@ -105,3 +105,4 @@ struct SalaryContentView: View { } } } + diff --git a/JShift/Views/Setting/SettingView.swift b/JShift/Views/Setting/SettingView.swift index 3e9dc12..d180ec9 100644 --- a/JShift/Views/Setting/SettingView.swift +++ b/JShift/Views/Setting/SettingView.swift @@ -27,7 +27,7 @@ struct SettingView: View { } } Section(footer: - Text("© 2024 Shin Kawakami") + Text("© 2024-2025 Shin Kawakami") .frame(maxWidth: .infinity, alignment: .center) .foregroundStyle(.secondary) ) { diff --git a/JShift/Views/Shift/ShiftSheetView.swift b/JShift/Views/Shift/DateShiftView.swift similarity index 80% rename from JShift/Views/Shift/ShiftSheetView.swift rename to JShift/Views/Shift/DateShiftView.swift index 2fb8aa2..97e748f 100644 --- a/JShift/Views/Shift/ShiftSheetView.swift +++ b/JShift/Views/Shift/DateShiftView.swift @@ -2,7 +2,7 @@ import RealmSwift import SwiftData import SwiftUI -struct ShiftSheetView: View { +struct DateShiftView: View { @Binding var selectedDate: Date @Query(sort: \Job.order) private var jobs: [Job] @Query private var otJobs: [OneTimeJob] @@ -35,15 +35,65 @@ struct ShiftSheetView: View { private var dateOtJobs: [OneTimeJob] { otJobs.filter { $0.date.isSameDay(selectedDate) } } - private var paymentDayJobs: [Job] { - jobs.filter { job in + private var paymentDayJobsWithSalary: [(job: Job, salary: Int)] { + let salaryDataByJob = Dictionary( + uniqueKeysWithValues: SalaryManager.shared + .getSalaryData(date: selectedDate, jobs: jobs, dateMode: .month) + .map { ($0.job.id, $0) } + ) + + return jobs.compactMap { job in + guard job.displayPaymentDay else { return nil } let paymentDay = job.getPaymentDay(year: selectedDate.year, month: selectedDate.month) - return paymentDay.isSameDay(selectedDate) && job.displayPaymentDay + guard paymentDay.isSameDay(selectedDate) else { return nil } + guard let salaryData = salaryDataByJob[job.id] else { return nil } + let amountInt: Int + if salaryData.isConfirmed { + amountInt = Int(salaryData.confirmedSalary) + } else { + amountInt = Int(salaryData.forecastSalary) + } + guard amountInt > 0 else { return nil } + return (job: job, salary: amountInt) } } var body: some View { NavigationStack { + HStack { + Text("\(selectedDate.toString(.weekday))") + .font(.title3.bold()) + Spacer() + HStack { + Button( + action: { + showOTJobAddSheet = true + }, + label: { + Image(systemName: "plus.circle.dashed") + Text("単発") + } + ) + .controlSize(.mini) + .buttonStyle(.borderedProminent) + .buttonBorderShape(.capsule) + Spacer().frame(width: 8) + Button( + action: { + showAddEventSheet = true + }, + label: { + Image(systemName: "plus.circle") + Text("長期") + } + ) + .controlSize(.mini) + .buttonStyle(.borderedProminent) + .buttonBorderShape(.capsule) + .disabled(jobs.isEmpty) + } + } + .padding(.horizontal, 16) ScrollView { ForEach(dateEvents) { event in Group { @@ -66,14 +116,13 @@ struct ShiftSheetView: View { } .padding(.horizontal) } - ForEach(paymentDayJobs) { job in + ForEach(paymentDayJobsWithSalary, id: \.job.id) { paymentDayJob in Group { - Divider() - PaymentDayRowView(job: job, date: selectedDate) + PaymentDayRowView(job: paymentDayJob.job, date: selectedDate, salary: paymentDayJob.salary) } .padding(.horizontal) } - if dateEvents.isEmpty && dateOtJobs.isEmpty && paymentDayJobs.isEmpty && suggestedEvents.isEmpty{ + if dateEvents.isEmpty && dateOtJobs.isEmpty && paymentDayJobsWithSalary.isEmpty && suggestedEvents.isEmpty{ Divider() Text("予定がありません") .bold() @@ -104,33 +153,6 @@ struct ShiftSheetView: View { await CalendarManager.shared.syncGoogleCalendar(skipSyncCalendarList: true) } .frame(maxWidth: .infinity) - .toolbar { - ToolbarItem(placement: .topBarLeading) { - Text("\(selectedDate.toString(.weekday))") - .font(.title3.bold()) - } - ToolbarItem(placement: .topBarTrailing) { - Button( - action: { - showOTJobAddSheet = true - }, - label: { - Image("custom.pencil.and.list.clipboard.badge.plus") - } - ) - } - ToolbarItem(placement: .topBarTrailing) { - Button( - action: { - showAddEventSheet = true - }, - label: { - Image(systemName: "plus") - } - ) - .disabled(jobs.isEmpty) - } - } } .onChange(of: selectedDate) { suggestedEvents = getSuggestEvents(selectedDate) diff --git a/JShift/Views/Shift/Parts/CalendarView.swift b/JShift/Views/Shift/Parts/CalendarView.swift index aa752e3..bd81e49 100644 --- a/JShift/Views/Shift/Parts/CalendarView.swift +++ b/JShift/Views/Shift/Parts/CalendarView.swift @@ -133,7 +133,12 @@ struct CalendarView: UIViewRepresentable { let paymentDayJob = parent.jobs.first { $0.getPaymentDay(year: dateComponents.year ?? 0, month: dateComponents.month ?? 0).isSameDay(dateComponents.date ?? Date()) && $0.displayPaymentDay } if let paymentDayJob = paymentDayJob { - return createCustomDecoration(dayJob: dayJob, dayOTJobs: dayOTJobs, paymentDayJob: paymentDayJob, dateEvents: dateEvents) + let paymentJobSalary = SalaryManager.shared + .getSalaryData(date: dateComponents.date ?? Date(), jobs: [paymentDayJob], dateMode: .month) + .first + if let paymentJobSalary = paymentJobSalary, (paymentJobSalary.confirmedSalary > 0 || paymentJobSalary.forecastSalary > 0) { + return createCustomDecoration(dayJob: dayJob, dayOTJobs: dayOTJobs, paymentDayJob: paymentDayJob, dateEvents: dateEvents) + } } if let dayJob = dayJob { return .default(color: UIColor(dayJob.color.toColor())) @@ -152,6 +157,7 @@ struct CalendarView: UIViewRepresentable { UIImage(named: "custom.yensign.badge", in: nil, with: UIImage.SymbolConfiguration(paletteColors: [UIColor(.secondary), UIColor(paymentDayJob.color.toColor())])), size: .large ) } + return .image(UIImage(systemName: "yensign"), color: UIColor(paymentDayJob.color.toColor()), size: .large) } diff --git a/JShift/Views/Shift/Parts/PaymentDayRowView.swift b/JShift/Views/Shift/Parts/PaymentDayRowView.swift index ec547ae..a240774 100644 --- a/JShift/Views/Shift/Parts/PaymentDayRowView.swift +++ b/JShift/Views/Shift/Parts/PaymentDayRowView.swift @@ -4,30 +4,25 @@ import SwiftUI struct PaymentDayRowView: View { let job: Job let date: Date - @State private var salary = 0 + let salary: Int @ViewBuilder var body: some View { - if salary > 0 { - HStack(alignment: .center) { - Rectangle() - .frame(width: 4, height: 32) - .cornerRadius(2) - .foregroundStyle(job.color.toColor()) - Text("\(job.name)給料日") - .bold() - .lineLimit(1) - Spacer() - Text("\(salary)円") - .lineLimit(2) - .font(.caption) - .foregroundStyle(.secondary) - .multilineTextAlignment(.center) - } - .onAppear { - let salaryData = SalaryManager.shared.getSalaryData(date: date, jobs: [job], dateMode: .month).first! - salary = salaryData.isConfirmed ? salaryData.confirmedSalary : salaryData.forecastSalary - } + Divider() + HStack(alignment: .center) { + Rectangle() + .frame(width: 4, height: 32) + .cornerRadius(2) + .foregroundStyle(job.color.toColor()) + Text("\(job.name)給料日") + .bold() + .lineLimit(1) + Spacer() + Text("\(salary)円") + .lineLimit(2) + .font(.caption) + .foregroundStyle(.secondary) + .multilineTextAlignment(.center) } } } diff --git a/JShift/Views/Shift/ShiftView.swift b/JShift/Views/Shift/ShiftView.swift index 705de33..0f8e361 100644 --- a/JShift/Views/Shift/ShiftView.swift +++ b/JShift/Views/Shift/ShiftView.swift @@ -23,6 +23,7 @@ struct ShiftView: View { ) .frame(height: 470) Spacer() + DateShiftView(selectedDate: $selectedDate) } .onAppear { if isInitial && !isWelcomePresented { @@ -48,16 +49,6 @@ struct ShiftView: View { } } } - .sheet(isPresented: $isSheetPresented) { - ShiftSheetView(selectedDate: $selectedDate) - .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading) - .presentationDetents([.height(240), .large]) - .presentationCornerRadius(18) - .presentationBackground(.bar) - .presentationBackgroundInteraction(.enabled(upThrough: .large)) - .interactiveDismissDisabled() - .bottomMaskForSheet() - } } } }