David's Capstone Project

Hey everyone, my name is David, I’m from Austria (not Australia :slight_smile:) and this is the beginning of my capstone project for the Launch Your First App program.

I started in the IT back in 2011 as a web and java developer while I was studying business informatics. I graduated 2016 as Master of Science in Engeneering and began to work as an Application Manager (2nd to 3rd lvl Support). I’ve been learning iOS for 3 months - one of em with CWC+.

Ultimately, my goal for learning iOS development is to become an indie app developer besides my job as an Application Manager.

I’m looking forward to updating this project log as I progress to completing my capstone project!

If you have any questions. Feel free to ask.

2 Likes

App idea

A very big hobby is (american) football and I already did some API calls to fetch data from a sports API in the assignments and I’ll extend them and create a football app.

You will get to view

  • the teams, their rosters, their coaches/staffs, season schedule, game infos (with time delay / no live ticker feature at the beginning) or some pregame data
  • the player infos and statistics
  • a daily transaction ticker, where you see contract extensions, releases or trades (maybe paid feature)

Furthermore I could app the following features later:
push notifications for favorite teams/players or scores in games
predicting the matches and gathering points if correct - social feature
game live ticker (paid feature)
draft overview (and maybe mock draft)

1 Like

Day 1

I know, most of the people are designing their icon later but I’m annoyed of the default app icon when you run it on your device or in the simulator.
So I made a first draft of my app icon.

What do you guys think about it? :slight_smile:

180

Day 2

My first Figma view. The app entry’s list view of teams. The background color should change according to the teams “home” colors, the name according to the teams name and the logo according to its logo.

i set the opacity of the background to 0.7 but it darkens the whole view. In reality, only the background and the tabbar at the bottom should have an opacity of 0.7 and 0.5 - the rest an opacity of 1.

What do you guys think? :slight_smile:

Design is ready.
Let’s start the coding part :smiley:

Hi guys,

short update from my side.

The developing process is ongoing and my app is about 75% ready.

The harder part is choosing a name for my app. I’d like to have a short solid name which is sounding like an “earworm” but every idea from myself does not sound very well.

Hopefully, I’m getting better ideas.

Cheers

Hi guys,

it’s been quite a while since my last post, but I was very busy setting up the in app purchases, testing everything and setting up my homepage (I choose WordPress) and publishing my homepage.

So far, so good. Here are some insights of my app:






Everything is working quite fine and my next chapter would be the meta data and the submission of the app. I’m very excited for the next steps and I’m very satisfied on how my app works, performs and looks like.

I hope, you also like it :slight_smile:

Cheers
David

1 Like

Hi guys,

short update from my side. The testing via TestFlight is ongoing and I already got some feedback from my testers and they encountered two crashes (unwrapping nil). I already fixed the issue and uploaded a new version for my testers. I’m very hyped for TestFlight because I’ve never encountered this error but my testers did and they already helped me a lot.

Feel free to write a PM or reply directly to this blog if you also want to test my app.

I‘m also trying to find a good name for my app. Maybe some of my testers will come up with a good idea. I‘m also thinking about a small goody for the winner.

Something like a lifelong free access to my liveticker - is it possible to create promocodes for a certain time?

Cheers David

1 Like

Hi guys,

I was very busy in the last weeks and let the testers do their work.

I improved some of the UI experience and readability of the text according to the users feedback. I also adapted my tab view to a custom tab view. Unfortunately, I ran into a problem while coding the tab view.

How can I align the tab buttons at the bottom?

Here is the code:

//
//  MainTabView.swift
//  Football Tracker
//
//  Created by David Laczkovits on 10.03.25.
//

import SwiftUI

enum TabbedItems: Int, CaseIterable{
    case teams = 0
    case transactions
    case gameplan
    case liveticker
    
    var title: String{
        switch self {
        case .teams:
            return "Teams"
        case .transactions:
            return "Transactions"
        case .gameplan:
            return "Game Plan"
        case .liveticker:
            return "Live Ticker"
        }
    }
    
    var iconName: String{
        switch self {
        case .teams:
            return "person.3.fill"
        case .transactions:
            return "dollarsign.circle.fill"
        case .gameplan:
            return "calendar"
        case .liveticker:
            return "play.tv.fill"
        }
    }
}

struct MainTabView: View {
    
    @State var selectedTab = 0
    
    @Environment(\.openURL) var openURL
    @Environment(\.colorScheme) var colorScheme
    @State private var askForAttachment = false
    @State private var showEmail = false
    @State private var langCode = "en"
    @State private var email = SupportEmail(toAddress: "support@laczkovits.info",
                                     subject: "Support Email from Football Index App",
                                     messageHeader: "Please describe your issue below")
    
    var body: some View {
            ZStack {
                Image("background")
                    .resizable()
                    .opacity(0.5)
                    .ignoresSafeArea()
                
                NavigationStack {
                    TabView(selection: $selectedTab) {
                        TeamsListView()
                            .tag(0)

                        TransactionDetailView()
                            .tag(1)

                        ScoreboardView()
                            .tag(2)

                        LiveGameListView()
                            .tag(3)
                    }
                    .toolbar {
                        ToolbarItem(placement: .navigationBarTrailing) {
                            Button {
                                askForAttachment.toggle()
                            } label: {
                                HStack {
                                    Text("Email Support")
                                        .font(.smallHeadline)
                                    Image(systemName: "envelope.circle.fill")
                                        .font(.bigHeadline)
                                }
                                .foregroundStyle(colorScheme == .light ? .black : .white)
                            }
                        }
                    }
                    .sheet(isPresented: $showEmail) {
                        MailView(supportEmail: $email) { result in
                            switch result {
                            case .success:
                                print("Email sent")
                            case .failure(let error):
                                print(error.localizedDescription)
                            }
                        }
                    }
                    .confirmationDialog("", isPresented: $askForAttachment) {
                        Button(LocalizedStringKey("Yes")) {
                            if email.data == nil {
                                email.send(openURL: openURL)
                            } else {
                                if MailView.canSendMail {
                                    showEmail.toggle()
                                } else {
                                    print("""
                                    This device does not support email
                                    \(email.body)
                                    """
                                    )
                                }
                            }
                        }
                        Button(LocalizedStringKey("No")) {
                            email.send(openURL: openURL)
                        }
                    } message: {
                        Text(LocalizedStringKey("Do you use the Apple Mail App?"))
                    }
                }
                
                ZStack(alignment:.bottom) {
                    HStack{
                        ForEach((TabbedItems.allCases), id: \.self){ item in
                            Button{
                                selectedTab = item.rawValue
                            } label: {
                                CustomTabItem(imageName: item.iconName, title: item.title, isActive: (selectedTab == item.rawValue))
                            }
                        }
                    }
                    .padding(6)
                }
                .frame(height: 70, alignment: .bottom)

                .background(.blue.opacity(0.2))
                .cornerRadius(35)
                .padding(.horizontal, 26)
            }
            .ignoresSafeArea()
        }
    }


extension MainTabView{
    func CustomTabItem(imageName: String, title: String, isActive: Bool) -> some View{
        HStack(spacing: 10){
            Spacer()
            Image(systemName: imageName)
                .resizable()
                .renderingMode(.template)
                .foregroundColor(isActive ? .black : .gray)
                .frame(width: 20, height: 20)
            if isActive{
                Text(title)
                    .font(.system(size: 14))
                    .foregroundColor(isActive ? .black : .gray)
            }
            Spacer()
        }
        .frame(width: isActive ? .infinity : 60, height: 60)
        .background(isActive ? .blue.opacity(0.4) : .clear)
        .cornerRadius(30)
    }
}

#Preview {
    MainTabView()
}

Any hint or help is appreciated.

Unfortunately, a Spacer is not working.

TiA.

Cheers
David

I just fixed it :slight_smile:

I will publish this version again for my testers and give them one or two more weeks and afterwards, I’ll try submitting my app.

Let’s see what Apple’s feedback will be.

Cheers
David

Unfortunately, I’m stuck at one more problem.

I don’t want to display the tabview buttons at my TeamInfoView

but nothing happens at

.toolbar(.hidden, for: .tabBar)

Here is the code from my TabView:

//
//  MainTabView.swift
//  Football Tracker
//
//  Created by David Laczkovits on 10.03.25.
//

import SwiftUI

enum TabbedItems: Int, CaseIterable{
    case teams = 0
    case transactions
    case gameplan
    case liveticker
    
    var title: String{
        switch self {
        case .teams:
            return "Teams"
        case .transactions:
            return "Transactions"
        case .gameplan:
            return "Game Plan"
        case .liveticker:
            return "Live Ticker"
        }
    }
    
    var iconName: String{
        switch self {
        case .teams:
            return "person.3.fill"
        case .transactions:
            return "dollarsign.circle.fill"
        case .gameplan:
            return "calendar"
        case .liveticker:
            return "play.tv.fill"
        }
    }
}

struct MainTabView: View {
    
    @State var selectedTab = 0
    
    @Environment(\.openURL) var openURL
    @Environment(\.colorScheme) var colorScheme
    @State private var askForAttachment = false
    @State private var showEmail = false
    @State private var langCode = "en"
    @State private var email = SupportEmail(toAddress: "support@laczkovits.info",
                                     subject: "Support Email from Football Index App",
                                     messageHeader: "Please describe your issue below")
    
    var body: some View {
        
        ZStack {
            Image("background")
                .resizable()
                .opacity(0.5)
                .ignoresSafeArea()
                
            GeometryReader { geo in
                NavigationStack {
                    TabView(selection: $selectedTab) {
                        TeamsListView()
                            .tag(0)
                            
                        TransactionDetailView()
                            .tag(1)

                        ScoreboardView()
                            .tag(2)

                        LiveGameListView()
                            .tag(3)
                    }
                    .toolbar {
                        ToolbarItem(placement: .navigationBarTrailing) {
                            Button {
                                askForAttachment.toggle()
                            } label: {
                                HStack {
                                    Text("Email Support")
                                        .font(.smallHeadline)
                                    Image(systemName: "envelope.circle.fill")
                                        .font(.bigHeadline)
                                }
                                .foregroundStyle(colorScheme == .light ? .black : .white)
                            }
                        }
                    }
                    .sheet(isPresented: $showEmail) {
                        MailView(supportEmail: $email) { result in
                            switch result {
                            case .success:
                                print("Email sent")
                            case .failure(let error):
                                print(error.localizedDescription)
                            }
                        }
                    }
                    .confirmationDialog("", isPresented: $askForAttachment) {
                        Button(LocalizedStringKey("Yes")) {
                            if email.data == nil {
                                email.send(openURL: openURL)
                            } else {
                                if MailView.canSendMail {
                                    showEmail.toggle()
                                } else {
                                    print("""
                                    This device does not support email
                                    \(email.body)
                                    """
                                    )
                                }
                            }
                        }
                        Button(LocalizedStringKey("No")) {
                            email.send(openURL: openURL)
                        }
                    } message: {
                        Text(LocalizedStringKey("Do you use the Apple Mail App?"))
                    }
                }
                .frame(height: geo.size.height * 0.90)
                VStack {
                    Spacer()
                    ZStack(alignment: .bottom) {
                        HStack {
                            ForEach((TabbedItems.allCases), id: \.self){ item in
                                Button {
                                    selectedTab = item.rawValue
                                } label: {
                                    CustomTabItem(imageName: item.iconName, title: item.title, isActive: (selectedTab == item.rawValue))
                                }
                            }
                        }
                        .padding(6)
                    }
                    .frame(height: 70, alignment: .bottom)

                    .background(.blue.opacity(0.2))
                    .cornerRadius(35)
                    .padding(.horizontal, 26)
                }
                .padding(.bottom, 30)
            }
            .ignoresSafeArea()
        }
            
    }
}


extension MainTabView{
    func CustomTabItem(imageName: String, title: String, isActive: Bool) -> some View{
        HStack(spacing: 10){
            Spacer()
            Image(systemName: imageName)
                .resizable()
                .renderingMode(.template)
                .foregroundColor(isActive ? .black : .gray)
                .frame(width: 20, height: 20)
            if isActive{
                Text(title)
                    .font(.system(size: 14))
                    .foregroundColor(isActive ? .black : .gray)
            }
            Spacer()
        }
        .frame(width: isActive ? .infinity : 60, height: 60)
        .background(isActive ? .blue.opacity(0.4) : .clear)
        .cornerRadius(30)
    }
}

#Preview {
    MainTabView()
}

Here is the code from my TeamInfoView

//
//  TeamInfoView.swift
//  Football Tracker
//
//  Created by David Laczkovits on 11.03.25.
//

import SwiftUI
import TelemetryDeck

struct TeamInfoView: View {
    
    @State private var teamInfo : TeamDetail?
    @State private var record : Record?
    @State private var venue : Venue?
    @State private var animationOffset = CGFloat(200)
    @State var selectedTeam : Team
    @State private var conferences : [ConferenceLeague]?
    @State private var standings : LiveStandingResponse?
    @State private var division = ""
    @State private var region = ""
    
    var body: some View {
        ZStack {
            Image("background")
                .resizable()
                .opacity(0.5)
                .ignoresSafeArea()
            
            VStack {
                ZStack {
                    Color("\(selectedTeam.slug ?? "")-primary")
                        .frame(height: 250)
                        .ignoresSafeArea()
                    VStack {
                        if let urlString = selectedTeam.logos?[0].href {
                            AsyncImage(url: URL(string: urlString)!, scale: 5) { image in
                                image.frame(width:50)
                            } placeholder: {
                                ProgressView()
                            }
                        }
                        
                        Text(selectedTeam.displayName ?? "")
                            .foregroundStyle(.white)
                            .font(.bigHeadline)
                    }
                    .padding(.top)
                }
                VStack {
                    ScrollView(showsIndicators: false) {
                        VStack(alignment: .leading, spacing: 20) {
                            ZStack {
                                RoundedRectangle(cornerRadius: 15)
                                    .opacity(0.8)
                                    .foregroundStyle(.fontBackground)
                                VStack {
                                    Text(LocalizedStringKey("Records"))
                                        .font(.screenHeading)
//                                        .padding(.top, -20)
                                    HStack {
                                        Text(LocalizedStringKey("Standings:"))
                                        Text("\(teamInfo?.teaminfo?.standingSummary ?? "")")
                                    }
                                    .font(.bigHeadline)
                                    
                                    if standings?.response?.isEmpty == false {
                                        HStack {
                                            Spacer()
                                            Text("Position")
                                            Spacer()
                                            Text("Team")
                                            Spacer()
                                            Text(LocalizedStringKey("Streak"))
                                            Spacer()
                                        }
                                        .font(.featuredNumber)
                                        .bold()
                                        
                                        ForEach(conferences ?? [ConferenceLeague]()) { conference in
                                            if (conference.teams?.one == selectedTeam.displayName || conference.teams?.two == selectedTeam.displayName ||  conference.teams?.three == selectedTeam.displayName || conference.teams?.four == selectedTeam.displayName) {
                                                ForEach(standings?.response ?? [LiveStanding]()) { standing in
                                                    if (standing.conference == conference.name && standing.division == conference.region) {
                                                        HStack {
                                                            Spacer()
                                                            Text(String(standing.position ?? 0))
                                                            Spacer()
                                                            Text(standing.team?.name ?? "")
                                                            Spacer()
                                                            Text(standing.streak ?? "")
                                                            Spacer()
                                                        }
                                                        .font(.featuredNumber)
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                            
                            
                            ZStack {
                                RoundedRectangle(cornerRadius: 15)
                                    .opacity(0.8)
                                    .foregroundStyle(.fontBackground)
                                VStack {
                                    Text(LocalizedStringKey("Stadium"))
                                        .font(.screenHeading)
                                    
                                    VStack {
                                        Text(venue?.fullName ?? "")
                                            .padding(.bottom)
                                        Text(venue?.address?.city ?? "")
                                        Text(venue?.address?.state ?? "")
                                        Text(venue?.address?.zipCode ?? "")
                                        Text(venue?.address?.country ?? "")
                                            .padding(.bottom)
                                        HStack {
                                            Text(LocalizedStringKey("Grass:"))
                                            Text(venue?.grass ?? true ? LocalizedStringKey("Yes") : LocalizedStringKey("No"))
                                        }
                                        HStack {
                                            Text(LocalizedStringKey("Indoor:"))
                                            Text(venue?.indoor ?? true ? LocalizedStringKey("Yes") : LocalizedStringKey("No"))
                                        }
                                        .padding(.bottom)
                                    }
                                    
                                    if let url = URL(string: venue?.images?[0].href ?? "") {
                                        AsyncImage(url: url) { image in
                                            image.resizable().scaledToFit().clipShape(.rect(cornerRadius: 15))
                                        } placeholder: {
                                            ProgressView()
                                        }
                                    }
                                }
                                .font(.featuredNumber)
                            }
                        
                            HStack {
                                Spacer()
                                
                                NavigationLink {
                                    PlayerListView(selectedTeam: selectedTeam)
                                } label: {
                                    ZStack {
                                        RoundedRectangle(cornerRadius: 15)
                                            .frame(width: 100, height: 100)
                                            .shadow(radius: 15)
                                        
                                        VStack {
                                            Image(systemName: "person.3")
                                                .font(.largeTitle)
                                            Text("Roster")
                                        }
                                        .foregroundStyle(.white)
                                        
                                    }
                                }
                                
                                Spacer()
                                
                                NavigationLink {
                                    NewsDetailView(selectedTeam: selectedTeam)
                                } label: {
                                    ZStack {
                                        RoundedRectangle(cornerRadius: 15)
                                            .frame(width: 100, height: 100)
                                            .shadow(radius: 15)
                                        
                                        VStack {
                                            Image(systemName: "info.square.fill")
                                                .font(.largeTitle)
                                            Text("News")
                                        }
                                        .foregroundStyle(.white)
                                        
                                    }
                                }
                                
                                Spacer()
                            }
                            HStack {
                                Spacer()
                                
                                NavigationLink {
                                    TeamTransactionDetailView(selectedTeam: selectedTeam)
                                } label: {
                                    ZStack {
                                        RoundedRectangle(cornerRadius: 15)
                                            .frame(width: 100, height: 100)
                                            .shadow(radius: 15)
                                        
                                        VStack {
                                            Image(systemName: "dollarsign.circle.fill")
                                                .font(.largeTitle)
                                            Text(LocalizedStringKey("Transfers"))
                                        }
                                        .foregroundStyle(.white)
                                    }
                                }
                                
                                Spacer()
                                
                                NavigationLink {
                                    ScoreboardView(selectedTeam: selectedTeam)
                                } label: {
                                    ZStack {
                                        RoundedRectangle(cornerRadius: 15)
                                            .frame(width: 100, height: 100)
                                            .shadow(radius: 15)
                                        
                                        VStack {
                                            Image(systemName: "calendar")
                                                .font(.largeTitle)
                                            Text("Game Plan")
                                        }
                                        .foregroundStyle(.white)
                                    }
                                }
                                
                                Spacer()
                            }
                            
                            ForEach(record?.items ?? [Itm]()) { itm in
                                Text("\(itm.name ?? ""): \(itm.displayValue ?? "")")
                                    .font(.bigHeadline)
                                ForEach(itm.stats) { stat in
                                    Text("\(stat.displayName ?? ""): \(stat.displayValue ?? "")")
                                        .font(.featuredText)
                                        .padding(.top, -20)
                                }
                            }
                            
                        }
                        .padding()
                    }
                }
                .offset(y:animationOffset)
                .padding(.bottom,80)
                Spacer()
            }
            .ignoresSafeArea()
            .onAppear {
                Task {
                    await teamInfo = DataService().getInfoByTeam(selectedTeam: selectedTeam)
                    await record = DataService().getRecordsByTeam(selectedTeam: selectedTeam)
                    await venue = DataService().getVenueByTeam(selectedTeam: selectedTeam)
                    await conferences = DataService().getAllConferences()
                    await standings = DataService().getLiveStandings()
                }
                withAnimation {
                    animationOffset = 0
                }
                TelemetryDeck.signal("OpenedTeamDetailView \(selectedTeam.displayName ?? "")")
            }
            .onDisappear {
                animationOffset = 200
            }
            .toolbar(.hidden, for: .tabBar)
        }
    }
}

Will appreciate any hints.

TiA.

Cheers
David

Im stuck at one more problem.

The first is with the display of the tab view in the other pages.

The second one which I’m facing currently is another problem with my tab view. I changed a bit and did some animation stuff on the tab bar so that it looks fancy and I’m very satisfied with the outcome but unfortunately, it doesn’t switch between the pages.

When i change the value in line 62 from @State **var** selectedTab : Tab = .teams to for e.g. @State var selectedTab : Tab = .transactions the tab view button changes and the view also changes, but clicking the button has no effects besides the animation.

Here is the code from my MainTabView:

//
//  MainTabView.swift
//  Football Tracker
//
//  Created by David Laczkovits on 10.03.25.
//

import SwiftUI

enum Tab: Int, Identifiable, CaseIterable, Comparable {
    static func < (lhs: Tab, rhs: Tab) -> Bool {
        lhs.rawValue < rhs.rawValue
    }
    
    case teams, transactions, gameplan, liveticker
    
    internal var id: Int { rawValue }
    
    var icon: String {
        switch self {
        case .teams:
            return "person.3.fill"
        case .transactions:
            return "dollarsign.circle.fill"
        case .gameplan:
            return "calendar"
        case .liveticker:
            return "play.tv.fill"
        }
    }
    
    var title: String {
        switch self {
        case .teams:
            return "Teams"
        case .transactions:
            return "Trades"
        case .gameplan:
            return "Plan"
        case .liveticker:
            return "Ticker"
        }
    }
    
    var color: Color {
        switch self {
        case .teams:
            return .teams
        case .transactions:
            return .transactions
        case .gameplan:
            return .gameplan
        case .liveticker:
            return .liveticker
        }
    }
}


struct MainTabView: View {
    
    @State var selectedTab : Tab = .teams
    
    @Environment(\.openURL) var openURL
    @Environment(\.colorScheme) var colorScheme
    @State private var askForAttachment = false
    @State private var showEmail = false
    @State private var langCode = "en"
    @State private var email = SupportEmail(toAddress: "support@laczkovits.info",
                                     subject: "Support Email from Football Index App",
                                     messageHeader: "Please describe your issue below")
    
    var body: some View {
        GeometryReader { geo in
            ZStack {
                Image("background")
                    .resizable()
                    .opacity(0.5)
                    .ignoresSafeArea()
                
                VStack {
                    NavigationStack {
                        TabView(selection: $selectedTab) {
                            TeamsListView()
                                .tag(Tab.teams)

                            TransactionDetailView()
                                .tag(Tab.transactions)

                            ScoreboardView()
                                .tag(Tab.gameplan)

                            LiveGameListView()
                                .tag(Tab.liveticker)
                        }
                        .toolbar {
                            ToolbarItem(placement: .navigationBarTrailing) {
                                Button {
                                    askForAttachment.toggle()
                                } label: {
                                    HStack {
                                        Text("Email Support")
                                            .font(.smallHeadline)
                                        Image(systemName: "envelope.circle.fill")
                                            .font(.bigHeadline)
                                    }
                                    .foregroundStyle(colorScheme == .light ? .black : .white)
                                }
                            }
                        }
                        .sheet(isPresented: $showEmail) {
                            MailView(supportEmail: $email) { result in
                                switch result {
                                case .success:
                                    print("Email sent")
                                case .failure(let error):
                                    print(error.localizedDescription)
                                }
                            }
                        }
                        .confirmationDialog("", isPresented: $askForAttachment) {
                            Button(LocalizedStringKey("Yes")) {
                                if email.data == nil {
                                    email.send(openURL: openURL)
                                } else {
                                    if MailView.canSendMail {
                                        showEmail.toggle()
                                    } else {
                                        print("""
                                        This device does not support email
                                        \(email.body)
                                        """
                                        )
                                    }
                                }
                            }
                            Button(LocalizedStringKey("No")) {
                                email.send(openURL: openURL)
                            }
                        } message: {
                            Text(LocalizedStringKey("Do you use the Apple Mail App?"))
                        }
                    }
                
                    TabBarView3(selectedTab: selectedTab)
                        .padding(.bottom, 80)
                        .frame(height: 70)
                        
                }
                
                
                
            }
            .ignoresSafeArea()
        }
            
    }
}

#Preview {
    MainTabView()
}


And here is the code from the custom bar with the animation stuff:

//
//  TabBarView3.swift
//  CustomTabBar
//
//  
//

import SwiftUI

struct TabBarView3: View {
    
    @State var selectedTab : Tab
    
    var body: some View {
        TabsLayoutView(selectedTab : selectedTab)
                .padding()
                .background(
                    Capsule()
                        .fill(.blue.opacity(0.2))
                )
                .frame(height: 70)
                .shadow(radius: 30)
    }
}

fileprivate struct TabsLayoutView: View {
    @State var selectedTab: Tab
    @Namespace var namespace
    
    var body: some View {
        HStack {
            ForEach(Tab.allCases) { tab in
                TabButton(tab: tab, selectedTab: $selectedTab, namespace: namespace)
            }
        }
    }
    
    private struct TabButton: View {
        let tab: Tab
        @Binding var selectedTab: Tab
        var namespace: Namespace.ID
        @State private var selectedOffset: CGFloat = 0
        @State private var rotationAngle: CGFloat = 0
        
        var body: some View {
            Button {
                withAnimation(.easeInOut) {
                    selectedTab = tab
                }
                
                selectedOffset = -60
                if tab < selectedTab {
                    rotationAngle += 360
                } else {
                    rotationAngle -= 360
                }
                DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
                    selectedOffset = 0
                    if tab < selectedTab {
                        rotationAngle += 720
                    } else {
                        rotationAngle -= 720
                    }
                }
            } label: {
                ZStack {
                    if isSelected {
                        Capsule()
                            .fill(tab.color.opacity(0.2))
                            .matchedGeometryEffect(id: "Selected Tab", in: namespace)
                    }
                    HStack(spacing: 10) {
                        Image(systemName: tab.icon)
                            .font(.system(size: 20, weight: .semibold, design: .rounded))
                            .foregroundColor(isSelected ? tab.color : .black.opacity(0.6))
                            .rotationEffect(.degrees(rotationAngle))
                            .scaleEffect(isSelected ? 1 : 0.9)
                            .animation(.easeInOut, value: rotationAngle)
                            .opacity(isSelected ? 1 : 0.7)
                            .padding(.leading, isSelected ? 20 : 0)
                            .padding(.horizontal, selectedTab != tab ? 10 : 0)
                            .offset(y: selectedOffset)
                            .animation(.default, value: selectedOffset)
                        
                        if isSelected {
                            Text(tab.title)
                                .font(.system(size: 20, weight: .semibold, design: .rounded))
                                .foregroundColor(tab.color)
                                .padding(.trailing, 20)
                        }
                    }
                    .padding(.vertical, 10)
                }
            }
            .buttonStyle(.plain)
        }
        
        private var isSelected: Bool {
            selectedTab == tab
        }
    }
}
struct TabBarView3_Previews: PreviewProvider {
    static var previews: some View {
        TabBarView3(selectedTab: Tab.teams)
            .frame(height: 70)
            .padding(.horizontal)
    }
}

Any help appreciated.

Cheers
David

Hi,
short update from my side. I just fixed the Binding issue. Next will be the issue with the tab bar not hiding. Afterwards it should be a pretty good stand for submitting the app
Cheers
David

Hi,
I was able to remove the tabbar from the teaminfoview, roster views, transaction views.
Unfortunately I’m stuck at removing it for the scoreboard and gameview.
When I enter

@Binding var selectedEvent : FootballEvent? in the scoreboardview and call it from my mainview as following:

//
//  MainTabView.swift
//  Football Tracker
//
//  Created by David Laczkovits on 10.03.25.
//

import SwiftUI

enum Tab: Int, Identifiable, CaseIterable, Comparable {
    static func < (lhs: Tab, rhs: Tab) -> Bool {
        lhs.rawValue < rhs.rawValue
    }
    
    case teams, transactions, gameplan, liveticker
    
    internal var id: Int { rawValue }
    
    var icon: String {
        switch self {
        case .teams:
            return "person.3.fill"
        case .transactions:
            return "dollarsign.circle.fill"
        case .gameplan:
            return "calendar"
        case .liveticker:
            return "play.tv.fill"
        }
    }
    
    var title: String {
        switch self {
        case .teams:
            return "Teams"
        case .transactions:
            return "Trades"
        case .gameplan:
            return "Plan"
        case .liveticker:
            return "Ticker"
        }
    }
    
    var color: Color {
        switch self {
        case .teams:
            return .teams
        case .transactions:
            return .transactions
        case .gameplan:
            return .gameplan
        case .liveticker:
            return .liveticker
        }
    }
}


struct MainTabView: View {
    @State var selectedTab : Tab = .teams
    
    @Environment(\.openURL) var openURL
    @Environment(\.colorScheme) var colorScheme
    
    @State private var askForAttachment = false
    @State private var showEmail = false
    @State private var langCode = "en"
    @State private var email = SupportEmail(toAddress: "support@laczkovits.info",
                                            subject: "Support Email from Football Index App",
                                            messageHeader: "Please describe your issue below")

    @State private var selectedTeam: Team? = nil
    @State private var selectedEvent:FootballEvent? = nil


    var body: some View {
        ZStack {
            Image("background")
                .resizable()
                .opacity(0.5)
                .ignoresSafeArea()

            VStack {
                NavigationStack {
                    TabView(selection: $selectedTab) {
                        TeamsListView(selectedTeam: $selectedTeam)
                        .tag(Tab.teams)

                        TransactionDetailView()
                            .tag(Tab.transactions)

                        ScoreboardView(selectedEvent: $selectedEvent)
                            .tag(Tab.gameplan)

                        LiveGameListView()
                            .tag(Tab.liveticker)
                    }
                    .animation(.easeInOut(duration: 0.3), value: selectedTab)
                    .transition(.slide)
                    
                    .sheet(isPresented: $showEmail) {
                        MailView(supportEmail: $email) { result in
                            switch result {
                            case .success:
                                print("Email sent")
                            case .failure(let error):
                                print(error.localizedDescription)
                            }
                        }
                    }
                    .confirmationDialog("", isPresented: $askForAttachment) {
                        Button(LocalizedStringKey("Yes")) {
                            if email.data == nil {
                                email.send(openURL: openURL)
                            } else {
                                if MailView.canSendMail {
                                    showEmail.toggle()
                                } else {
                                    print("This device does not support email\n\(email.body)")
                                }
                            }
                        }
                        Button(LocalizedStringKey("No")) {
                            email.send(openURL: openURL)
                        }
                    } message: {
                        Text(LocalizedStringKey("Do you use the Apple Mail App?"))
                    }
                }

                TabBarView3(selectedTab: $selectedTab)
                    .padding(.bottom, 80)
                    .frame(height: 70)
            }
        }
        .toolbar {
            ToolbarItem(placement: .navigationBarTrailing) {
                Button {
                    askForAttachment.toggle()
                } label: {
                    HStack {
                        Text("Email Support")
                            .font(.smallHeadline)
                        Image(systemName: "envelope.circle.fill")
                            .font(.bigHeadline)
                    }
                    .foregroundStyle(colorScheme == .light ? .black : .white)
                }
            }
        }
        .fullScreenCover(item: $selectedTeam) { team in
            TeamInfoView(selectedTeam: team)
        }
        .fullScreenCover(item: $selectedEvent) { event in
            GameDetailView(event: event)
        }
        .ignoresSafeArea()
    }
}


#Preview {
    MainTabView()
}


it won’t work and give me an error:
The compiler is unable to type-check this expression in reasonable time; try breaking up the expression into distinct sub-expressions
Unfortunately, I don’t quite know where the error is…still bugfixing

BTW. I also have a new app logo.