Summary
Transition ADAMANT Messenger (adamant-iOS) to native macOS-aligned UI patterns and system styling when running on macOS (Mac Catalyst), removing custom visual workarounds and aligning with current Apple Human Interface Guidelines. This includes replacing manual styling (custom backgrounds, selection layers, hardcoded colors/insets) with semantic system colors, native list/split configurations, and modern configuration APIs to ensure correct behavior in Light/Dark modes, accent color variations, and future macOS updates.
Motivation
With recent macOS updates, parts of the UI (split layout, selection states, grouped blocks, toolbars, insets) no longer render correctly or consistently. Some selection backgrounds, block highlighting, and layout spacing appear visually broken or non-native.
The root cause is not a single bug but accumulated custom styling and layout adjustments that diverge from system-driven behavior.
Goals:
- Eliminate fragile, OS-sensitive UI workarounds
- Adopt native split view and sidebar patterns
- Ensure correct rendering in Light/Dark mode and with different system accent colors
- Improve forward compatibility with future macOS releases
- Reduce maintenance burden caused by custom visual logic
Detailed description
1. Sidebar and Selection Behavior
Current issues:
- Custom selection backgrounds conflict with system highlight behavior
- Selected/active states may not match macOS sidebar expectations
- Focus state may not be visually distinguishable
Actions:
- Remove manual selected/highlighted background drawing
- Migrate list cells to modern configuration APIs (
UIListContentConfiguration, UIBackgroundConfiguration)
- Use system sidebar/list configurations instead of custom background layers
- Ensure selection updates via updateConfiguration(using:) based on
UICellConfigurationState
- Avoid hardcoded selection colors
Expected result:
Native macOS sidebar behavior with correct highlight, focus, and accent color adaptation.
2. Split View Architecture
Current issues:
- Inconsistent layout between primary and secondary columns
- Incorrect resizing behavior when window is resized
- Manual width handling instead of system-driven behavior
Actions:
- Ensure
UISplitViewController is used in .doubleColumn style
- Configure
preferredDisplayMode appropriately for macOS behavior
- Remove manual layout adjustments that simulate master-detail behavior
- Validate primary column width configuration and resizing constraints
Expected result:
Stable, native two-pane layout consistent with macOS conventions.
3. System Colors and Materials
Current issues:
- Hardcoded RGB values for backgrounds and separators
- Custom alpha/blur combinations that break in Dark Mode or high contrast
- Inconsistent appearance under different system accent colors
Actions:
- Replace custom colors with semantic system colors (label, secondaryLabel, systemBackground, secondarySystemBackground, separator, tertiarySystemFill, etc.)
- Avoid fixed opacity values unless required
- Test with:
- Light and Dark modes
- Different system accent colors
- Increase Contrast
- Reduce Transparency
Expected result:
Visual consistency across themes and accessibility settings.
4. Toolbar, Navigation Bar, and Insets
Current issues:
- Hardcoded top insets
- Layout assumptions tied to iOS navigation bar behavior
- Content overlapping or misaligned under macOS title/toolbar
Actions:
- Remove fixed height calculations for top bars
- Avoid manual status bar offsets
- Review
UINavigationBarAppearance and UIToolbarAppearance usage
- Let safe areas and system layout guides drive positioning
Expected result:
Correct alignment with macOS unified title/toolbar styling.
5. Cards, Grouped Blocks, and Rounded Containers
Current issues:
- Custom “card” visuals conflicting with system grouping
- Mismatched corner radius vs selection highlight
- Layout artifacts during window resizing
Actions:
- Prefer system background grouping instead of layered
CALayer styling
- Minimize custom corner radius unless essential
- Avoid stacking background layers that override system selection behavior
Expected result:
Cleaner layout with fewer visual artifacts during resizing and state changes.
6. macOS-Specific Interaction Patterns
Current issues:
- Long-press logic reused from iOS for context actions
- Hover and right-click behavior inconsistent with macOS expectations
- Limited keyboard shortcut support
Actions:
- Ensure context menus use
UIContextMenuInteraction / UIMenu
- Validate right-click behavior on macOS
- Review focus handling
- Improve keyboard shortcut support where applicable
Expected result:
Proper macOS interaction model without iOS-centric behavior leaks.
Notes
- This is not a purely visual refactor; it improves architectural alignment with Apple platform guidelines
- Changes should be incremental and validated screen by screen (Chats, Wallet, Settings)
- Avoid introducing new custom visual abstractions during migration
- Performance during window resizing must be monitored to prevent layout thrashing
- Testing must include real macOS hardware, not only simulator
Screenshots or videos
Alternatives
- Maintain current custom styling and patch individual breakages per macOS release.
This approach increases long-term maintenance cost and risk of regression.
- Fork macOS-specific UI layer.
Higher complexity and code duplication, not preferred unless architectural divergence becomes necessary.
Preferred approach: adopt system-native styling and configurations within the existing Catalyst architecture.
Proposed technical implementation
Some useful (or not) code parts:
// 1) Native sidebar-style cell using modern configurations (UIKit / Catalyst)
//
// Use this for the Chats list / Accounts list on macOS.
// Key idea: don't draw selection backgrounds manually.
// Let UIBackgroundConfiguration + UIListContentConfiguration handle it.
final class SidebarCell: UITableViewCell {
private var titleText: String = ""
private var subtitleText: String?
func configure(title: String, subtitle: String? = nil) {
titleText = title
subtitleText = subtitle
setNeedsUpdateConfiguration()
}
override func updateConfiguration(using state: UICellConfigurationState) {
// Content
var content = UIListContentConfiguration.sidebarCell().updated(for: state)
content.text = titleText
content.secondaryText = subtitleText
content.textProperties.color = .label
content.secondaryTextProperties.color = .secondaryLabel
contentConfiguration = content
// Background
var bg = UIBackgroundConfiguration.listSidebarCell().updated(for: state)
backgroundConfiguration = bg
// Avoid interfering with system selection appearance.
selectedBackgroundView = nil
multipleSelectionBackgroundView = nil
}
}
// 2) Applying native list appearance to a UITableView (iOS + macOS Catalyst)
//
// This removes the need for custom separators and manual grouped backgrounds.
// It's particularly helpful for Settings/Wallet-style grouped screens.
func applyNativeListAppearance(_ tableView: UITableView) {
tableView.backgroundColor = .systemBackground
tableView.separatorColor = .separator
tableView.separatorInset = .zero
tableView.cellLayoutMarginsFollowReadableWidth = true
// Pick one depending on your screen. For Settings-like views:
tableView.separatorStyle = .singleLine
tableView.estimatedRowHeight = 52
tableView.rowHeight = UITableView.automaticDimension
// If you previously used a custom table footer to hide empty separators:
tableView.tableFooterView = UIView()
}
// 3) A "do not hardcode colors" helper: semantic palette for cards/blocks
//
// Use these instead of RGB constants when drawing "cards" or section backgrounds.
// It will adapt to Light/Dark, accessibility contrast, and macOS accent settings.
enum SystemPalette {
static let pageBackground: UIColor = .systemBackground
static let groupBackground: UIColor = .secondarySystemBackground
static let elevatedBackground: UIColor = .tertiarySystemBackground
static let primaryText: UIColor = .label
static let secondaryText: UIColor = .secondaryLabel
static let separator: UIColor = .separator
static let fill: UIColor = .tertiarySystemFill
}
// 4) Replace "manual highlight layers" with background configuration for a card-like view
//
// This is useful for "blocks" in Wallet/Settings, where selection/highlight looked broken.
// It uses UIBackgroundConfiguration so the system can manage states consistently.
final class CardLikeCell: UITableViewCell {
private var titleText: String = ""
func configure(title: String) {
titleText = title
setNeedsUpdateConfiguration()
}
override func updateConfiguration(using state: UICellConfigurationState) {
var content = UIListContentConfiguration.valueCell().updated(for: state)
content.text = titleText
content.textProperties.color = .label
contentConfiguration = content
var bg = UIBackgroundConfiguration.listGroupedCell().updated(for: state)
bg.backgroundColor = .secondarySystemBackground
bg.cornerRadius = 12
bg.strokeColor = .separator
bg.strokeWidth = 1 / UIScreen.main.scale
backgroundConfiguration = bg
selectedBackgroundView = nil
multipleSelectionBackgroundView = nil
}
}
// 5) Proper double-column split view controller configuration (UIKit / Catalyst)
//
// This makes the layout behave like a native macOS two-pane UI.
// Put this where you build your root controller for macOS/Catalyst mode.
func makeRootSplitViewController(primary: UIViewController,
secondary: UIViewController) -> UISplitViewController {
let svc = UISplitViewController(style: .doubleColumn)
svc.setViewController(primary, for: .primary)
svc.setViewController(secondary, for: .secondary)
// Typical macOS behavior: show both columns side-by-side when possible.
svc.preferredDisplayMode = .oneBesideSecondary
// Tune width for sidebar-like primary column.
svc.preferredPrimaryColumnWidthFraction = 0.32
svc.minimumPrimaryColumnWidth = 260
svc.maximumPrimaryColumnWidth = 420
return svc
}
// 6) Remove fragile top inset hacks and rely on safe area
//
// If you have code that adds manual top padding for "navigation bar height",
// replace it with safeAreaInsets-based layout.
final class SafeAreaPinnedViewController: UIViewController {
private let contentView = UIView()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemBackground
contentView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(contentView)
NSLayoutConstraint.activate([
contentView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
contentView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
contentView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor),
contentView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor)
])
}
}
// 7) Context menu that behaves correctly on macOS (right-click) and iOS (long press)
//
// Prefer UIContextMenuInteraction/UIMenu over custom "long press" logic.
// Attach this to message bubbles, chat rows, wallet rows, etc.
final class ContextMenuHost: NSObject, UIContextMenuInteractionDelegate {
func attach(to view: UIView) {
let interaction = UIContextMenuInteraction(delegate: self)
view.addInteraction(interaction)
}
func contextMenuInteraction(_ interaction: UIContextMenuInteraction,
configurationForMenuAtLocation location: CGPoint) -> UIContextMenuConfiguration? {
UIContextMenuConfiguration(identifier: nil, previewProvider: nil) { _ in
let copy = UIAction(title: "Copy", image: UIImage(systemName: "doc.on.doc")) { _ in
UIPasteboard.general.string = "..."
}
let share = UIAction(title: "Share…", image: UIImage(systemName: "square.and.arrow.up")) { _ in
// Present share sheet from your controller
}
return UIMenu(title: "", children: [copy, share])
}
}
}
// 8) Quick runtime switch: Catalyst-only tweaks (when absolutely needed)
//
// Use sparingly. The main goal is to NOT branch styling heavily,
// but sometimes you need small adjustments for macOS behavior.
extension ProcessInfo {
static var isMacCatalystApp: Bool {
#if targetEnvironment(macCatalyst)
return true
#else
return false
#endif
}
}
func applyCatalystTweaksIfNeeded() {
guard ProcessInfo.isMacCatalystApp else { return }
// Example: prefer larger default content sizes for desktop readability
UILabel.appearance().adjustsFontForContentSizeCategory = true
}
Verification Checklist
Visual:
- Chats screen renders correctly in Light and Dark mode
- Sidebar selection uses native highlight and respects system accent color
- Wallet and Settings layouts maintain correct split behavior
- No overlapping content in title/toolbar area
- Grouped blocks look native and consistent
Interaction:
- Selection state remains correct when switching windows
- Right-click and context menus behave properly on macOS
- Window resizing does not cause layout glitches
- No flickering or redraw artifacts in lists
Accessibility:
- UI remains readable with Increase Contrast enabled
- UI behaves correctly with Reduce Transparency enabled
- No hardcoded color assumptions break visibility
Regression:
- iOS appearance remains unaffected
- No functional regressions in chat, wallet, or settings modules
Outcome:
ADAMANT Messenger on macOS behaves as a first-class native Mac app rather than an iOS app with visual overrides.
Summary
Transition ADAMANT Messenger (adamant-iOS) to native macOS-aligned UI patterns and system styling when running on macOS (Mac Catalyst), removing custom visual workarounds and aligning with current Apple Human Interface Guidelines. This includes replacing manual styling (custom backgrounds, selection layers, hardcoded colors/insets) with semantic system colors, native list/split configurations, and modern configuration APIs to ensure correct behavior in Light/Dark modes, accent color variations, and future macOS updates.
Motivation
With recent macOS updates, parts of the UI (split layout, selection states, grouped blocks, toolbars, insets) no longer render correctly or consistently. Some selection backgrounds, block highlighting, and layout spacing appear visually broken or non-native.
The root cause is not a single bug but accumulated custom styling and layout adjustments that diverge from system-driven behavior.
Goals:
Detailed description
1. Sidebar and Selection Behavior
Current issues:
Actions:
UIListContentConfiguration,UIBackgroundConfiguration)UICellConfigurationStateExpected result:
Native macOS sidebar behavior with correct highlight, focus, and accent color adaptation.
2. Split View Architecture
Current issues:
Actions:
UISplitViewControlleris used in.doubleColumnstylepreferredDisplayModeappropriately for macOS behaviorExpected result:
Stable, native two-pane layout consistent with macOS conventions.
3. System Colors and Materials
Current issues:
Actions:
Expected result:
Visual consistency across themes and accessibility settings.
4. Toolbar, Navigation Bar, and Insets
Current issues:
Actions:
UINavigationBarAppearanceandUIToolbarAppearanceusageExpected result:
Correct alignment with macOS unified title/toolbar styling.
5. Cards, Grouped Blocks, and Rounded Containers
Current issues:
Actions:
CALayerstylingExpected result:
Cleaner layout with fewer visual artifacts during resizing and state changes.
6. macOS-Specific Interaction Patterns
Current issues:
Actions:
UIContextMenuInteraction/UIMenuExpected result:
Proper macOS interaction model without iOS-centric behavior leaks.
Notes
Screenshots or videos
Alternatives
This approach increases long-term maintenance cost and risk of regression.
Higher complexity and code duplication, not preferred unless architectural divergence becomes necessary.
Preferred approach: adopt system-native styling and configurations within the existing Catalyst architecture.
Proposed technical implementation
Some useful (or not) code parts:
Verification Checklist
Visual:
Interaction:
Accessibility:
Regression:
Outcome:
ADAMANT Messenger on macOS behaves as a first-class native Mac app rather than an iOS app with visual overrides.