- Add getUnreadCount() endpoint to NotificationsServiceProtocol - Add NotificationUnreadCountResponse model - Add badgeCount and fetchUnreadCount() to NotificationsViewModel - Update markAsRead/markAllAsRead to decrement badge count - Create MainTabView with Home, Challenges, Clubs, Notifications tabs - Add unread badge on notification tab using .badge() modifier - Support injected ViewModel in NotificationsView for shared state - Add badge count tests to NotificationServiceTests - Fetch unread count on app launch and tab switch Co-Authored-By: Paperclip <noreply@paperclip.ing>
80 lines
2.2 KiB
Swift
80 lines
2.2 KiB
Swift
import SwiftUI
|
|
|
|
struct MainTabView: View {
|
|
@State private var selectedTab: AppTab = .home
|
|
@StateObject private var notificationVM = NotificationsViewModel()
|
|
|
|
var body: some View {
|
|
TabView(selection: $selectedTab) {
|
|
Group {
|
|
TrainingPlanView()
|
|
.tag(AppTab.home)
|
|
.tabItem {
|
|
Label(AppTab.home.title, systemImage: AppTab.home.icon)
|
|
}
|
|
|
|
ChallengesView()
|
|
.tag(AppTab.challenges)
|
|
.tabItem {
|
|
Label(AppTab.challenges.title, systemImage: AppTab.challenges.icon)
|
|
}
|
|
|
|
ClubsView()
|
|
.tag(AppTab.clubs)
|
|
.tabItem {
|
|
Label(AppTab.clubs.title, systemImage: AppTab.clubs.icon)
|
|
}
|
|
|
|
NotificationsView(viewModel: notificationVM)
|
|
.tag(AppTab.notifications)
|
|
.tabItem {
|
|
Label(AppTab.notifications.title, systemImage: AppTab.notifications.icon)
|
|
}
|
|
.badge(notificationVM.badgeCount)
|
|
}
|
|
}
|
|
.onAppear {
|
|
Task {
|
|
await notificationVM.fetchUnreadCount()
|
|
}
|
|
}
|
|
.onChange(of: selectedTab) { _, newTab in
|
|
if newTab == .notifications {
|
|
Task {
|
|
await notificationVM.fetchNotifications()
|
|
await notificationVM.fetchUnreadCount()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
enum AppTab: String, CaseIterable {
|
|
case home
|
|
case challenges
|
|
case clubs
|
|
case notifications
|
|
|
|
var title: String {
|
|
switch self {
|
|
case .home: return "Home"
|
|
case .challenges: return "Challenges"
|
|
case .clubs: return "Clubs"
|
|
case .notifications: return "Notifications"
|
|
}
|
|
}
|
|
|
|
var icon: String {
|
|
switch self {
|
|
case .home: return "house.fill"
|
|
case .challenges: return "flag.fill"
|
|
case .clubs: return "person.3.fill"
|
|
case .notifications: return "bell.fill"
|
|
}
|
|
}
|
|
}
|
|
|
|
#Preview {
|
|
MainTabView()
|
|
}
|