diff --git a/Flipcash/Core/Screens/Main/Home/HomeTabBar.swift b/Flipcash/Core/Screens/Main/Home/HomeTabBar.swift index 9dc1a5194..8c6508d82 100644 --- a/Flipcash/Core/Screens/Main/Home/HomeTabBar.swift +++ b/Flipcash/Core/Screens/Main/Home/HomeTabBar.swift @@ -9,7 +9,8 @@ import FlipcashUI /// The floating pill tab bar for the v2 UI. A Liquid Glass capsule holds one /// button per ``HomeTab``, with a white selection pill that slides to the active /// tab. Ported from Android's `NavigationBarV2` (Figma frame 9013-5434): -/// translucent capsule, white-20% sliding indicator, icons at full/half opacity. +/// translucent capsule, white-20% sliding indicator, white icons and labels in +/// both states. Only the profile photo dims when unselected. struct HomeTabBar: View { @Binding var selection: HomeTab @@ -80,7 +81,6 @@ struct HomeTabBar: View { .frame(height: Self.labelLineHeight) .accessibilityHidden(true) } - .opacity(selection == tab ? 1 : 0.5) .frame(width: itemWidth, height: Self.itemHeight) .contentShape(Capsule()) } @@ -110,6 +110,7 @@ struct HomeTabBar: View { private func icon(for tab: HomeTab) -> some View { if tab == .tipCard, let profileSlot { ProfileTabIcon(photo: profileSlot.preview, isSelected: tab == selection) + .opacity(tab == selection ? 1 : 0.5) .scaleEffect(Self.iconSize / ProfileTabIcon.slotSize) .frame(width: Self.iconSize, height: Self.iconSize) } else { diff --git a/Flipcash/Core/Screens/Main/Home/HomeTabView.swift b/Flipcash/Core/Screens/Main/Home/HomeTabView.swift index 7f46238f9..5b3214e91 100644 --- a/Flipcash/Core/Screens/Main/Home/HomeTabView.swift +++ b/Flipcash/Core/Screens/Main/Home/HomeTabView.swift @@ -38,18 +38,19 @@ struct HomeTabView: View { _selection = State(initialValue: initialTab) _hasOpenedChat = State(initialValue: initialTab == .chat) - // Color the tab glyphs per state: selected white, the rest secondary. - // The iOS 26 tab bar ignores UITabBar.unselectedItemTintColor, so drive - // it through a full item appearance instead. A transparent background + // Color the tab glyphs white in both states, as iOS 27 already does; the + // outline-vs-filled glyph carries the selection. The iOS 26 tab bar + // ignores UITabBar.unselectedItemTintColor, so drive it through a full + // item appearance instead. A transparent background // keeps the system's Liquid Glass. No-op on the legacy pill path, which // draws its own buttons rather than a `UITabBar`. if #available(iOS 26, *) { let items = UITabBarItemAppearance() - items.normal.iconColor = UIColor(Color.textSecondary) + items.normal.iconColor = UIColor(Color.textMain) items.selected.iconColor = UIColor(Color.textMain) // Labels per node 10642:1325: 10pt Avenir Demi, colored like the glyph above. let titleFont = UIFont.default(size: 10, weight: .semibold) - items.normal.titleTextAttributes = [.font: titleFont, .foregroundColor: UIColor(Color.textSecondary)] + items.normal.titleTextAttributes = [.font: titleFont, .foregroundColor: UIColor(Color.textMain)] items.selected.titleTextAttributes = [.font: titleFont, .foregroundColor: UIColor(Color.textMain)] let appearance = UITabBarAppearance() diff --git a/Flipcash/Core/Screens/Main/Home/TabBarBadgedIcon.swift b/Flipcash/Core/Screens/Main/Home/TabBarBadgedIcon.swift index 168862e85..427e7bd2e 100644 --- a/Flipcash/Core/Screens/Main/Home/TabBarBadgedIcon.swift +++ b/Flipcash/Core/Screens/Main/Home/TabBarBadgedIcon.swift @@ -48,7 +48,7 @@ enum TabBarBadgedIcon { .renderingMode(.template) .resizable() .scaledToFit() - .foregroundStyle(glyphColor(isSelected: isSelected)) + .foregroundStyle(Color.textMain) .frame(width: glyphSize, height: glyphSize) .overlay(alignment: .topTrailing) { Bubble(size: .regular, count: count, color: .unreadIndicator) @@ -59,15 +59,6 @@ enum TabBarBadgedIcon { .padding(.trailing, bubbleOverhang) } - /// The color the bar paints its template glyphs in for the state. iOS 27 - /// ignores the unselected `iconColor` from `HomeTabView` and paints every - /// glyph in the main text color, so the Chat glyph follows suit there. - private static func glyphColor(isSelected: Bool) -> Color { - if isSelected { return .textMain } - if #available(iOS 27, *) { return .textMain } - return .textSecondary - } - private static func image(of icon: some View) -> UIImage? { let renderer = ImageRenderer(content: icon) renderer.scale = UIScreen.main.scale diff --git a/Flipcash/Core/Screens/Main/Home/TabBarProfilePhoto.swift b/Flipcash/Core/Screens/Main/Home/TabBarProfilePhoto.swift index 42b5abc59..03fc4907a 100644 --- a/Flipcash/Core/Screens/Main/Home/TabBarProfilePhoto.swift +++ b/Flipcash/Core/Screens/Main/Home/TabBarProfilePhoto.swift @@ -160,8 +160,8 @@ final class TabBarProfilePhoto { /// /// The bar tints template glyphs per state, but a photo has to render as its /// own colours — so the unselected state is baked in here instead: the - /// thinner half-opacity ring, and the half opacity the pill applies to every - /// other icon. + /// thinner half-opacity ring, and the half opacity the pill draws the photo + /// at. static func render(_ photo: UIImage?) -> ItemImages? { guard let selected = image(of: ProfileTabIcon(photo: photo, isSelected: true)), let normal = image(of: ProfileTabIcon(photo: photo, isSelected: false).opacity(0.5))