Skip to content
This repository was archived by the owner on Feb 15, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 11 additions & 9 deletions JShift.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@
attributes = {
BuildIndependentTargetsInParallel = 1;
LastSwiftUpdateCheck = 1600;
LastUpgradeCheck = 1600;
LastUpgradeCheck = 2600;
TargetAttributes = {
5436B6092CE8DEEC00E8CBFA = {
CreatedOnToolsVersion = 16.0;
Expand Down Expand Up @@ -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;
Copy link

Copilot AI Nov 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ENABLE_APP_SANDBOX setting has been added to the target-specific build configuration, but the corresponding entitlements were removed from JShift.entitlements. For App Sandbox to work properly, the entitlements file should contain the com.apple.security.app-sandbox key set to true. Consider restoring the sandbox entitlements or removing the build setting.

Copilot uses AI. Check for mistakes.
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";
Expand All @@ -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;
Expand All @@ -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";
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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";
};
Expand Down Expand Up @@ -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;
Expand All @@ -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;
};
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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;
Expand Down
Binary file not shown.
4 changes: 0 additions & 4 deletions JShift/JShift.entitlements
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,5 @@
<array>
<string>CloudKit</string>
</array>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.files.user-selected.read-only</key>
<true/>
</dict>
</plist>
2 changes: 2 additions & 0 deletions JShift/Models/CalendarManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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
Expand Down
4 changes: 2 additions & 2 deletions JShift/Models/SwiftData/JobSchemaV1.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
7 changes: 3 additions & 4 deletions JShift/Views/ContentView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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)),
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

オンボーディングの説明がアップデートの規模を正確に反映していません。

PRの目的には「Liquid Glassデザインの実装」「メジャーバージョン更新」「新UIのオンボーディング追加」など大規模な変更が記載されていますが、オンボーディングの説明には「軽微な不具合の修正」としか書かれていません。

ユーザーに対してアップデートの重要性を適切に伝えるため、説明文をより具体的にすることを検討してください:

-                        .init(title: "iOS 26に対応", description: "iOS 26対応と軽微な不具合の修正", symbolName: "apple.logo", tintColor: UIColor(.green)),
+                        .init(title: "iOS 26に対応", description: "iOS 26の新デザイン「Liquid Glass」に対応し、UIを刷新しました", symbolName: "apple.logo", tintColor: UIColor(.green)),
🤖 Prompt for AI Agents
In JShift/Views/ContentView.swift around line 42, the onboarding item
description currently says "軽微な不具合の修正" which undersells the PR (major version
bump, Liquid Glass design, new onboarding UI). Update the title/description
string to reflect the actual scope—for example mention the Liquid Glass design
rollout, major version update, and new onboarding UI—while keeping existing
symbolName and tintColor; ensure the change uses the app's localization pattern
(if any) and keeps string formatting/escaping consistent.

],
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")!) })
)
}
)
Expand Down
3 changes: 2 additions & 1 deletion JShift/Views/Salary/SalaryContentView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -105,3 +105,4 @@ struct SalaryContentView: View {
}
}
}

2 changes: 1 addition & 1 deletion JShift/Views/Setting/SettingView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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)
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down Expand Up @@ -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 {
Expand All @@ -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()
Expand Down Expand Up @@ -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)
Expand Down
8 changes: 7 additions & 1 deletion JShift/Views/Shift/Parts/CalendarView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Comment on lines +136 to +141
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

給与データ取得のパフォーマンス懸念

calculateDecorationはカレンダーの各日付(最大31〜42日分)に対して呼び出され、ここでgetSalaryDataを毎回実行すると、以下の影響があります:

  • getSalaryDatagetWorkIntervalgetJobEvents、給与履歴のフィルタリングなど、比較的重い処理を含んでいます
  • decorationCacheはRealm更新や表示切替のたびにクリアされるため(69、81、100行目)、頻繁に再計算が発生します
  • UI描画パスで実行されるため、パフォーマンスに影響する可能性があります

改善案:

  • 月全体の給与データをCoordinatorレベルで事前計算してキャッシュすることを検討してください
  • または、給与データ取得を非同期化し、結果をキャッシュする仕組みを導入してください

補足:dateComponents.date ?? Date()のフォールバックは、dateComponents.datenilの場合に現在日時を使用しますが、意図した日付と異なる可能性があります。

}
if let dayJob = dayJob {
return .default(color: UIColor(dayJob.color.toColor()))
Expand All @@ -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)
}

Expand Down
Loading