Skip to content
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
78 changes: 0 additions & 78 deletions .github/workflows/claude-code-review.yml

This file was deleted.

64 changes: 0 additions & 64 deletions .github/workflows/claude.yml

This file was deleted.

10 changes: 9 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,15 @@ xcrun simctl launch booted com.barronroth.Cubby DISABLE_CLOUDKIT
- Use `asc` for App Store Connect status, build/version staging, review submission, and release/distribution operations.
- Use Xcode Cloud when local archive/signing is blocked by keychain or certificate access.
- `.asc/export-options-app-store.plist` contains App Store Connect export options for local `asc`/Xcode export flows.
- Current project settings should be verified before release; as of this update, marketing version is `1.0.4`, build is `70`, and deployment target is iOS `26.0`.
- Version/build numbers are release-sensitive. Before opening or updating any PR branch that can trigger Xcode Cloud/TestFlight/App Store distribution:
- Read the project values from `Cubby.xcodeproj/project.pbxproj`:
`rg -n "MARKETING_VERSION|CURRENT_PROJECT_VERSION" Cubby.xcodeproj/project.pbxproj`
- Check App Store Connect for already-uploaded builds:
`asc builds list --app 6751732388 --sort -uploadedDate --limit 20 --output table`
- Ensure `CURRENT_PROJECT_VERSION` is greater than every uploaded/submitted build for the same `MARKETING_VERSION`; if not, bump all `CURRENT_PROJECT_VERSION` occurrences to the next unused integer before pushing.
- Do not bump `MARKETING_VERSION` unless the user explicitly asks for a new App Store version or the release train requires it. For normal PR/TestFlight fixes, keep the current marketing version and only bump the build number.
- After pushing, monitor Xcode Cloud from GitHub with `gh pr checks --watch=false`; if it fails, inspect the Xcode Cloud details before bumping again.
- Branches intended to launch the Codex Xcode Cloud/TestFlight workflow should keep the `codex/` prefix.
- `fastlane/` is legacy. Historically it provided:
- `fastlane beta`: increment build number, build an App Store export, upload to TestFlight, wait for processing, distribute externally.
- `fastlane beta_internal`: same upload path without external distribution.
Expand Down
30 changes: 15 additions & 15 deletions Cubby.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,7 @@
CODE_SIGN_ENTITLEMENTS = Cubby/Cubby.Debug.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 86;
CURRENT_PROJECT_VERSION = 91;
DEVELOPMENT_TEAM = CVE9ZKS33D;
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
Expand All @@ -333,7 +333,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.0.8;
MARKETING_VERSION = 1.0.9;
PRODUCT_BUNDLE_IDENTIFIER = com.barronroth.Cubby;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
Expand All @@ -352,7 +352,7 @@
CODE_SIGN_ENTITLEMENTS = Cubby/Cubby.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 86;
CURRENT_PROJECT_VERSION = 91;
DEVELOPMENT_TEAM = CVE9ZKS33D;
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
Expand All @@ -369,7 +369,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.0.8;
MARKETING_VERSION = 1.0.9;
PRODUCT_BUNDLE_IDENTIFIER = com.barronroth.Cubby;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
Expand Down Expand Up @@ -503,10 +503,10 @@
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 86;
CURRENT_PROJECT_VERSION = 91;
GENERATE_INFOPLIST_FILE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 26.0;
MARKETING_VERSION = 1.0.8;
MARKETING_VERSION = 1.0.9;
PRODUCT_BUNDLE_IDENTIFIER = com.barronroth.CubbyTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = NO;
Expand All @@ -521,10 +521,10 @@
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 86;
CURRENT_PROJECT_VERSION = 91;
GENERATE_INFOPLIST_FILE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 26.0;
MARKETING_VERSION = 1.0.8;
MARKETING_VERSION = 1.0.9;
PRODUCT_BUNDLE_IDENTIFIER = com.barronroth.CubbyTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = NO;
Expand All @@ -538,9 +538,9 @@
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 86;
CURRENT_PROJECT_VERSION = 91;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0.8;
MARKETING_VERSION = 1.0.9;
PRODUCT_BUNDLE_IDENTIFIER = com.barronroth.CubbyUITests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = NO;
Expand All @@ -554,9 +554,9 @@
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 86;
CURRENT_PROJECT_VERSION = 91;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0.8;
MARKETING_VERSION = 1.0.9;
PRODUCT_BUNDLE_IDENTIFIER = com.barronroth.CubbyUITests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = NO;
Expand Down Expand Up @@ -618,10 +618,10 @@
};
F6E851580DBA413886332B51 /* XCRemoteSwiftPackageReference "MCEmojiPicker" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/izyumkin/MCEmojiPicker";
repositoryURL = "https://github.com/barronlroth/MCEmojiPicker";
requirement = {
kind = upToNextMajorVersion;
minimumVersion = 1.2.5;
kind = revision;
revision = 2391491cb0dcbba479ec8b3425b726d3e8617d19;
};
};
/* End XCRemoteSwiftPackageReference section */
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

62 changes: 2 additions & 60 deletions Cubby/Views/Items/ItemEmojiPickerButton.swift
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,7 @@ private struct ItemMCEmojiPickerController: UIViewControllerRepresentable {

switch isPresented {
case true:
if let emojiPicker = representableController.presentedViewController as? MCEmojiPickerViewController {
MCEmojiPickerCategoryBarRepair.schedule(in: emojiPicker.view)
if representableController.presentedViewController is MCEmojiPickerViewController {
return
}

Expand All @@ -119,9 +118,7 @@ private struct ItemMCEmojiPickerController: UIViewControllerRepresentable {
emojiPicker.feedBackGeneratorStyle = feedBackGeneratorStyle

context.coordinator.addPickerDismissingObserver()
representableController.present(emojiPicker, animated: true) {
MCEmojiPickerCategoryBarRepair.schedule(in: emojiPicker.view)
}
representableController.present(emojiPicker, animated: true)
case false:
if representableController.presentedViewController is MCEmojiPickerViewController,
context.coordinator.isPresented {
Expand Down Expand Up @@ -172,58 +169,3 @@ private struct ItemMCEmojiPickerController: UIViewControllerRepresentable {
private static let pickerDidDisappearNotification = Notification.Name("MCEmojiPickerDidDisappear")
}
}

private enum MCEmojiPickerCategoryBarRepair {
// MCEmojiPicker 1.2.5 appends category controls from draw(_:), so popover redraws can duplicate them.
private static let categoryCount = 9
private static let repairDelays: [TimeInterval] = [0, 0.05, 0.2, 0.45]

static func schedule(in rootView: UIView) {
repairDelays.forEach { delay in
DispatchQueue.main.asyncAfter(deadline: .now() + delay) {
repair(in: rootView)
}
}
}

private static func repair(in rootView: UIView) {
stackViews(in: rootView).forEach(repair)
}

private static func repair(_ stackView: UIStackView) {
let arrangedSubviews = stackView.arrangedSubviews
guard arrangedSubviews.count > categoryCount,
arrangedSubviews.allSatisfy(isCategoryView)
else { return }

let viewsToKeep = Set(arrangedSubviews.suffix(categoryCount).map { ObjectIdentifier($0) })
for view in arrangedSubviews where !viewsToKeep.contains(ObjectIdentifier(view)) {
stackView.removeArrangedSubview(view)
view.removeFromSuperview()
}

stackView.setNeedsLayout()
stackView.layoutIfNeeded()
stackView.arrangedSubviews.forEach {
$0.setNeedsLayout()
$0.setNeedsDisplay()
}
}

private static func isCategoryView(_ view: UIView) -> Bool {
String(reflecting: type(of: view)).contains("MCTouchableEmojiCategoryView")
}

private static func stackViews(in rootView: UIView) -> [UIStackView] {
var result = [UIStackView]()
if let stackView = rootView as? UIStackView {
result.append(stackView)
}

rootView.subviews.forEach {
result.append(contentsOf: stackViews(in: $0))
}

return result
}
}