Origin/ios/bugfix/czy#573
Merged
Merged
Conversation
There was a problem hiding this comment.
Pull request overview
This iOS-only PR fixes a number of issues in the WeDate ("没课约") feature plus a few unrelated polishing items. The bulk of the change introduces a centralized WeDateTheme.swift palette and replaces ad-hoc hex/UIColor(.dm,...) literals across the WeDate UI to enable proper dark mode. It also rewrites the course-schedule loading path with caching, request throttling, deferred section reloads (so paging animation isn't interrupted), bounds checks, and a loading state.
Changes:
- Add
WeDateTheme.swiftwith semantic color tokens; refactor ~20 WeDate view/VC files to use them and add panel/page/text/separator coverage for dark mode. - Rework
WeekMaping/ScheduleFact/WeDateCourseScheduleVC/CourseScheduleModelfor cached + throttled per-student schedule requests, fallback student data, defer-reload-while-scrolling, and a new "课表加载中" loading view. - Misc: stop tracking
Podfile.lock(gitignore + deletion), require interactive pop gesture inQAMainVC/ActivityMainViewController, fix wrong image name我的返回→Publish_backBtn, registerWeDateTheme.swiftin pbxproj.
Reviewed changes
Copilot reviewed 36 out of 38 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| .gitignore | Ignore Podfile.lock going forward. |
| cyxbs-applications/pro/iosApp/Podfile.lock | Removed from version control. |
| .../CyxbsMobile2019_iOS.xcodeproj/project.pbxproj | Add WeDateTheme.swift to project/build phases. |
| .../Discover_WeDate/WeDateTheme.swift | New centralized semantic color palette with light/dark values. |
| .../Discover_WeDate/WeDateVC.swift, WeDateTopView.swift | Switch backgrounds/title text to theme tokens; tweak title weight. |
| .../Discover_WeDate/TemporaryGroupVC.swift, FixedGroupVC.swift, GroupManageVC.swift | Theme adoption for search bar, table, prompt, swipe actions; small debug logging in fixed-group inquire. |
| .../Discover_WeDate/StudentTableViewCell.swift, GroupTableViewCell.swift, SearchResult/* cells & VCs | Apply panel/page background and themed text colors. |
| .../Discover_WeDate/RepeatName/* | Theme tokens for panel, table, buttons, text. |
| .../Discover_WeDate/CreateGroup*/* | Theme tokens for alert/sheet UI. |
| .../Discover_WeDate/ChooseGroup/* | Theme tokens for sheet, indicators, finish button states. |
| .../Discover_WeDate/BatchAdd/BatchAddVC.swift | Theme tokens incl. text view, separators, example labels. |
| .../Discover_WeDate/AddArrange/* | Theme tokens for collection cells and step VCs. |
| .../Discover_WeDate/BusyDetail/BusyDetailVC.swift | Theme tokens for panel, attributed strings, page control, separator. |
| .../Discover_WeDate/CourseSchedule/CourseScheduleModel.swift | Add fallback student, masked debug logs; failure callbacks no longer propagate errors. |
| .../Discover_WeDate/CourseSchedule/WeekMaping.swift | Add static cache + throttled OperationQueue request pipeline, bounds-checked period filling, debug summary log; merge moved to dedicated serial queue. |
| .../Discover_WeDate/CourseSchedule/ScheduleFact.swift | Loading flags, deferred section reloads while scrolling, bounded currentPage, themed today highlight, loadInitialSchedules API. |
| .../Discover_WeDate/CourseSchedule/ScheduleCollectionViewLayout.swift | Clamp landing page index into [0, numberOfPages-1]. |
| .../Discover_WeDate/CourseSchedule/ScheduleCollectionViewCell.swift | Theme tokens for busy/leisure/today cell variants. |
| .../Discover_WeDate/CourseSchedule/WeDateCourseScheduleVC.swift | Loading view, weak-self async, cache schedule for first stuNum, clamp "回到本周" target, gradient via theme. |
| .../Discover_SchoolBus/Views/SchoolBusMapView.m | Fix back-button image name to existing asset Publish_backBtn. |
| .../Center/QA/QA_Main/VC/QAMainVC.swift, .../Center/Activity/.../ActivityMainViewController.swift | Make inner list pan gesture require nav controller's interactive pop gesture to fail. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
62
to
85
| @@ -57,12 +76,15 @@ class CourseScheduleModel { | |||
| let student = StudentResultItem(dictionary: dic) | |||
| courseScheduleModel.student = student | |||
| } | |||
| debugLog("student success resolved=\(!courseScheduleModel.student.studentID.isEmpty)", stuNum: stuNum) | |||
| group.leave() | |||
| }, | |||
| failure: { task, error in | |||
| failure?(error) | |||
| debugLog("student failure error=\(error.localizedDescription), use fallback student", stuNum: stuNum) | |||
| group.leave() | |||
| }) | |||
Comment on lines
74
to
95
| private static func enqueueCourseScheduleRequest(stuNum: String) { | ||
| requestQueue.addOperation { | ||
| let semaphore = DispatchSemaphore(value: 0) | ||
| CourseScheduleModel.requestWithStuNum(stuNum) { courseScheduleModel in | ||
| cacheQueue.async { | ||
| courseScheduleCache[stuNum] = courseScheduleModel | ||
| let completions = pendingCourseScheduleCompletions.removeValue(forKey: stuNum) ?? [] | ||
| completions.forEach { $0(courseScheduleModel) } | ||
| semaphore.signal() | ||
| } | ||
| } failure: { error in | ||
| print(error) | ||
| cacheQueue.async { | ||
| let completions = pendingCourseScheduleCompletions.removeValue(forKey: stuNum) ?? [] | ||
| completions.forEach { $0(nil) } | ||
| semaphore.signal() | ||
| } | ||
| } | ||
| semaphore.wait() | ||
| Thread.sleep(forTimeInterval: 0.12) | ||
| } | ||
| } |
Comment on lines
+57
to
+72
| private static func requestCourseSchedule(stuNum: String, completion: @escaping (CourseScheduleModel?) -> Void) { | ||
| cacheQueue.async { | ||
| if let cachedModel = courseScheduleCache[stuNum] { | ||
| completion(cachedModel) | ||
| return | ||
| } | ||
|
|
||
| if pendingCourseScheduleCompletions[stuNum] != nil { | ||
| pendingCourseScheduleCompletions[stuNum]?.append(completion) | ||
| return | ||
| } | ||
|
|
||
| pendingCourseScheduleCompletions[stuNum] = [completion] | ||
| enqueueCourseScheduleRequest(stuNum: stuNum) | ||
| } | ||
| } |
• CourseScheduleModel.swift:恢复 failure 契约。课表接口失败会走 failure;学生信息接口失败仍用学号 fallback,不再导致成员被丢。 • WeekMaping.swift:去掉 OperationQueue + semaphore + Thread.sleep,改成非阻塞 FIFO 限流队列。 • WeekMaping.swift:缓存命中和请求完成的 completion 统一投递到 userInitiated 全局队列,不再直接在 cacheQueue 上执行外部闭包。 • 限流仍保留:最多 3 个课表请求同时进行,请求启动间隔至少 0.12s。
Comment on lines
+58
to
+76
| private static func requestCourseSchedule(stuNum: String, completion: @escaping (CourseScheduleModel?) -> Void) { | ||
| cacheQueue.async { | ||
| if let cachedModel = courseScheduleCache[stuNum] { | ||
| callbackQueue.async { | ||
| completion(cachedModel) | ||
| } | ||
| return | ||
| } | ||
|
|
||
| if pendingCourseScheduleCompletions[stuNum] != nil { | ||
| pendingCourseScheduleCompletions[stuNum]?.append(completion) | ||
| return | ||
| } | ||
|
|
||
| pendingCourseScheduleCompletions[stuNum] = [completion] | ||
| pendingRequestStuNums.append(stuNum) | ||
| scheduleNextCourseScheduleRequestIfNeeded() | ||
| } | ||
| } |
Comment on lines
+58
to
+65
| if self.shouldWaitForInitialSchedules { | ||
| self.fact?.loadInitialSchedules { [weak self] in | ||
| self?.showScheduleContent() | ||
| } | ||
| } else { | ||
| self.showScheduleContent() | ||
| self.fact?.loadInitialSchedules {} | ||
| } |
Comment on lines
+50
to
73
| if !stuNumAry.isEmpty { | ||
| CourseScheduleModel.requestWithStuNum(stuNumAry[0]) { [weak self] courseScheduleModel in | ||
| guard let self = self else { return } | ||
| self.nowWeek = courseScheduleModel.nowWeek | ||
| WeekMaping.cacheCourseSchedule(courseScheduleModel, for: self.stuNumAry[0]) | ||
| self.fact = ScheduleFact(stuNumAry: self.stuNumAry, dateVersion: courseScheduleModel.dateVersion, nowWeek: self.nowWeek) | ||
| self.fact?.delegate = self | ||
| // 添加回到本周按钮时需确保fact有值,否则点击会崩溃 | ||
| self.view.addSubview(self.button) | ||
| // 添加collectionView时需确保fact有值,否则会崩溃 | ||
| self.view.addSubview(self.collectionView) | ||
| } failure: { error in | ||
|
|
||
| if self.shouldWaitForInitialSchedules { | ||
| _ = self.collectionView | ||
| self.fact?.loadInitialSchedules { [weak self] in | ||
| self?.showScheduleContent() | ||
| } | ||
| } else { | ||
| self.showScheduleContent() | ||
| self.fact?.loadInitialSchedules {} | ||
| } | ||
| } failure: { [weak self] error in | ||
| print(error) | ||
| self?.hideLoadingView() | ||
| } | ||
| } else { | ||
| hideLoadingView() | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
原iOS版修复了若干问题,具体可以查看提交日志