From edfe97c6dc7ae571f622e79165f449aee7506caa Mon Sep 17 00:00:00 2001 From: Vladimir Dubovik Date: Fri, 4 Apr 2025 11:01:33 +0300 Subject: [PATCH] Commit --- Schedule ICTIS/ConnectingToNetworkView.swift | 32 ++++++++ Schedule ICTIS/ContentView.swift | 81 +++++++++++++------ .../{ => ErrorsView}/NetworkErrorView.swift | 6 +- Schedule ICTIS/LoadingView.swift | 24 +++--- Schedule ICTIS/Main/Views/ScheduleView.swift | 5 +- Schedule ICTIS/Model/TabBarModel.swift | 2 +- Schedule ICTIS/Settings/FavGroupsView.swift | 8 +- Schedule ICTIS/Settings/FavVPKView.swift | 10 ++- .../Settings/ScheduleGroupSettings.swift | 5 +- .../Settings/SelectingGroupView.swift | 14 ++-- .../Settings/SelectingVPKView.swift | 12 ++- Schedule ICTIS/Settings/SettingsView.swift | 6 +- Schedule ICTIS/TabBar/TabBarView.swift | 33 +++++--- 13 files changed, 169 insertions(+), 69 deletions(-) create mode 100644 Schedule ICTIS/ConnectingToNetworkView.swift rename Schedule ICTIS/{ => ErrorsView}/NetworkErrorView.swift (71%) diff --git a/Schedule ICTIS/ConnectingToNetworkView.swift b/Schedule ICTIS/ConnectingToNetworkView.swift new file mode 100644 index 0000000..7dcae08 --- /dev/null +++ b/Schedule ICTIS/ConnectingToNetworkView.swift @@ -0,0 +1,32 @@ +// +// LoadingView.swift +// Schedule ICTIS +// +// Created by Mironov Egor on 11.12.2024. +// + +import SwiftUI + +struct ConnectingToNetworkView: View { + @State private var isAnimating = false + var body: some View { + VStack { + Text("Ожидание сети") + .font(.custom("Montserrat-Medium", fixedSize: 18)) + Circle() + .trim(from: 0.2, to: 1.0) + .stroke(Color("blueColor"), lineWidth: 3) + .frame(width: 30, height: 30) + .rotationEffect(Angle(degrees: isAnimating ? 360 : 0)) + .animation( + Animation.linear(duration: 0.6).repeatForever(autoreverses: false), + value: isAnimating + ) + .onAppear { isAnimating = true } + } + } +} + +#Preview { + ConnectingToNetworkView() +} diff --git a/Schedule ICTIS/ContentView.swift b/Schedule ICTIS/ContentView.swift index e32bbb2..08a2901 100644 --- a/Schedule ICTIS/ContentView.swift +++ b/Schedule ICTIS/ContentView.swift @@ -8,35 +8,70 @@ import SwiftUI struct ContentView: View { - @State private var selectedTab: Int = 1 + @State private var selectedTab: TabBarModel = .schedule + @State private var isTabBarHidden = false @ObservedObject var vm: ScheduleViewModel @ObservedObject var networkMonitor: NetworkMonitor var body: some View { - TabView(selection: $selectedTab) { - Text("Tasks") - .tabItem { - Image(systemName: "books.vertical") - Text("Задания") - } - .tag(0) - - MainView(vm: vm, networkMonitor: networkMonitor) - .tabItem { - Image(systemName: "house") - Text("Расписание") - } - .tag(1) - - SettingsView(vm: vm) - .tabItem { - Image(systemName: "gear") - Text("Настройки") - } - .tag(2) + ZStack (alignment: .bottom) { + TabView(selection: $selectedTab) { + Text("Tasks") + .tag(TabBarModel.tasks) + + MainView(vm: vm, networkMonitor: networkMonitor) + .tag(TabBarModel.schedule) + .background { + if !isTabBarHidden { + HideTabBar { + print("TabBar is hidden") + isTabBarHidden = true + } + } + } + + SettingsView(vm: vm, networkMonitor: networkMonitor) + .tag(TabBarModel.settings) + } + TabBarView(selectedTab: $selectedTab) } - .accentColor(Color("blueColor")) .onAppear { vm.fetchWeekSchedule() } } } + +struct HideTabBar: UIViewRepresentable { + var result: () -> () + func makeUIView(context: Context) -> UIView { + let view = UIView(frame: .zero) + view.backgroundColor = .clear + + DispatchQueue.main.async { + if let tabController = view.tabController { + tabController.tabBar.isHidden = true + result() + } + } + return view + } + func updateUIView(_ uiView: UIView, context: Context) { + + } +} + +extension UIView { + var tabController: UITabBarController? { + if let controller = sequence(first: self, next: { + $0.next + }).first(where: { $0 is UITabBarController}) as? UITabBarController { + return controller + } + return nil + } +} + +#Preview { + @Previewable @StateObject var vm1 = ScheduleViewModel() + @Previewable @StateObject var vm2 = NetworkMonitor() + ContentView(vm: vm1, networkMonitor: vm2) +} diff --git a/Schedule ICTIS/NetworkErrorView.swift b/Schedule ICTIS/ErrorsView/NetworkErrorView.swift similarity index 71% rename from Schedule ICTIS/NetworkErrorView.swift rename to Schedule ICTIS/ErrorsView/NetworkErrorView.swift index a45f8ea..d37e257 100644 --- a/Schedule ICTIS/NetworkErrorView.swift +++ b/Schedule ICTIS/ErrorsView/NetworkErrorView.swift @@ -8,6 +8,7 @@ import SwiftUI struct NetworkErrorView: View { + var message: String var body: some View { VStack { Spacer() @@ -15,17 +16,16 @@ struct NetworkErrorView: View { Image(systemName: "wifi.slash") .font(.system(size: 60, weight: .light)) .frame(width: 70, height: 70) - Text("Восстановите подключение к интернету чтобы мы могли загрузить расписание") + Text(message) .font(.custom("Montserrat-Medium", fixedSize: 15)) .padding(.top, 5) } .padding(.horizontal, 30) - .padding(.top, UIScreen.main.bounds.height/8) Spacer() } } } #Preview { - NetworkErrorView() + NetworkErrorView(message: "Восстановите подключение к интернету чтобы мы смогли загрузить расписание") } diff --git a/Schedule ICTIS/LoadingView.swift b/Schedule ICTIS/LoadingView.swift index 2708e4f..70e6b3b 100644 --- a/Schedule ICTIS/LoadingView.swift +++ b/Schedule ICTIS/LoadingView.swift @@ -2,24 +2,28 @@ // LoadingView.swift // Schedule ICTIS // -// Created by Mironov Egor on 11.12.2024. +// Created by Mironov Egor on 04.04.2025. // import SwiftUI struct LoadingView: View { - @Binding var isLoading: Bool + @State private var isAnimating = false + var body: some View { - ZStack { - Color("background") - .ignoresSafeArea() - ProgressView() - .progressViewStyle(CircularProgressViewStyle(tint: .secondary)) - .scaleEffect(1) - } + Circle() + .trim(from: 0.2, to: 1.0) + .stroke(Color("blueColor"), lineWidth: 3) + .frame(width: 30, height: 30) + .rotationEffect(Angle(degrees: isAnimating ? 360 : 0)) + .animation( + Animation.linear(duration: 0.6).repeatForever(autoreverses: false), + value: isAnimating + ) + .onAppear { isAnimating = true } } } #Preview { - LoadingView(isLoading: .constant(true)) + LoadingView() } diff --git a/Schedule ICTIS/Main/Views/ScheduleView.swift b/Schedule ICTIS/Main/Views/ScheduleView.swift index 50ce42d..a294dea 100644 --- a/Schedule ICTIS/Main/Views/ScheduleView.swift +++ b/Schedule ICTIS/Main/Views/ScheduleView.swift @@ -48,7 +48,7 @@ struct ScheduleView: View { private var onlineContent: some View { Group { if vm.errorInNetwork == .timeout { - NetworkErrorView() + NetworkErrorView(message: "Проверьте подключение к интернету") } else if vm.isLoading { LoadingScheduleView() } else if vm.errorInNetwork != .invalidResponse { @@ -114,7 +114,8 @@ struct ScheduleView: View { } else { let filteredSubjects = subjects.filter { $0.day == Int16(vm.selectedIndex) } if (filteredSubjects.isEmpty || vm.week != 0) && !hasClassesToShow { - NetworkErrorView() + ConnectingToNetworkView() + .padding(.top, 100) } else { ForEach(filteredSubjects, id: \.self) { subject in if (vm.showOnlyChoosenGroup == "Все" || subject.group == vm.showOnlyChoosenGroup) && vm.week == 0 { diff --git a/Schedule ICTIS/Model/TabBarModel.swift b/Schedule ICTIS/Model/TabBarModel.swift index 51a1e7b..13b1bf5 100644 --- a/Schedule ICTIS/Model/TabBarModel.swift +++ b/Schedule ICTIS/Model/TabBarModel.swift @@ -8,7 +8,7 @@ import SwiftUI enum TabBarModel: String, CaseIterable { - case schedule = "house" case tasks = "books.vertical" + case schedule = "house" case settings = "gear" } diff --git a/Schedule ICTIS/Settings/FavGroupsView.swift b/Schedule ICTIS/Settings/FavGroupsView.swift index 990a856..4dc3018 100644 --- a/Schedule ICTIS/Settings/FavGroupsView.swift +++ b/Schedule ICTIS/Settings/FavGroupsView.swift @@ -9,6 +9,7 @@ import SwiftUI struct FavGroupsView: View { @ObservedObject var vm: ScheduleViewModel + @ObservedObject var networkMonitor: NetworkMonitor var firstFavGroup = (UserDefaults.standard.string(forKey: "group") ?? "") var secondFavGroup = (UserDefaults.standard.string(forKey: "group2") ?? "") var thirdFavGroup = (UserDefaults.standard.string(forKey: "group3") ?? "") @@ -74,7 +75,7 @@ struct FavGroupsView: View { HStack { Spacer() if firstFavGroup == "" || secondFavGroup == "" || thirdFavGroup == "" { - NavigationLink(destination: SelectingGroupView(vm: vm, firstFavGroup: firstFavGroup, secondFavGroup: secondFavGroup, thirdFavGroup: thirdFavGroup)) { + NavigationLink(destination: SelectingGroupView(vm: vm, networkMonitor: networkMonitor, firstFavGroup: firstFavGroup, secondFavGroup: secondFavGroup, thirdFavGroup: thirdFavGroup)) { HStack { Image(systemName: "plus") .foregroundColor(.white) @@ -87,7 +88,7 @@ struct FavGroupsView: View { } } } - .padding(.bottom, 50) + .padding(.bottom, 90) } .background(Color("background")) } @@ -95,5 +96,6 @@ struct FavGroupsView: View { #Preview { @Previewable @StateObject var vm = ScheduleViewModel() - FavGroupsView(vm: vm) + @Previewable @StateObject var vm2 = NetworkMonitor() + FavGroupsView(vm: vm, networkMonitor: vm2) } diff --git a/Schedule ICTIS/Settings/FavVPKView.swift b/Schedule ICTIS/Settings/FavVPKView.swift index 633d9a8..0832805 100644 --- a/Schedule ICTIS/Settings/FavVPKView.swift +++ b/Schedule ICTIS/Settings/FavVPKView.swift @@ -2,13 +2,14 @@ // FavGroupsView.swift // Schedule ICTIS // -// Created by G412 on 05.03.2025. +// Created by Egor Mironov on 05.03.2025. // import SwiftUI struct FavVPKView: View { @ObservedObject var vm: ScheduleViewModel + @ObservedObject var networkMonitor: NetworkMonitor var firstFavVPK = (UserDefaults.standard.string(forKey: "vpk1") ?? "") var secondFavVPK = (UserDefaults.standard.string(forKey: "vpk2") ?? "") var thirdFavVPK = (UserDefaults.standard.string(forKey: "vpk3") ?? "") @@ -74,7 +75,7 @@ struct FavVPKView: View { HStack { Spacer() if firstFavVPK == "" || secondFavVPK == "" || thirdFavVPK == "" { - NavigationLink(destination: SelectingVPKView(vm: vm, firstFavVPK: firstFavVPK, secondFavVPK: secondFavVPK, thirdFavVPK: thirdFavVPK)) { + NavigationLink(destination: SelectingVPKView(vm: vm, networkMonitor: networkMonitor, firstFavVPK: firstFavVPK, secondFavVPK: secondFavVPK, thirdFavVPK: thirdFavVPK)) { HStack { Image(systemName: "plus") .foregroundColor(.white) @@ -87,7 +88,7 @@ struct FavVPKView: View { } } } - .padding(.bottom, 50) + .padding(.bottom, 90) } .background(Color("background")) } @@ -95,5 +96,6 @@ struct FavVPKView: View { #Preview { @Previewable @StateObject var vm = ScheduleViewModel() - FavVPKView(vm: vm) + @Previewable @StateObject var vm2 = NetworkMonitor() + FavVPKView(vm: vm, networkMonitor: vm2) } diff --git a/Schedule ICTIS/Settings/ScheduleGroupSettings.swift b/Schedule ICTIS/Settings/ScheduleGroupSettings.swift index aee6421..8d905f6 100644 --- a/Schedule ICTIS/Settings/ScheduleGroupSettings.swift +++ b/Schedule ICTIS/Settings/ScheduleGroupSettings.swift @@ -9,9 +9,10 @@ import SwiftUI struct ScheduleGroupSettings: View { @ObservedObject var vm: ScheduleViewModel + @ObservedObject var networkMonitor: NetworkMonitor var body: some View { VStack { - NavigationLink(destination: FavGroupsView(vm: vm)) { + NavigationLink(destination: FavGroupsView(vm: vm, networkMonitor: networkMonitor)) { HStack { Text("Избранное расписание") .font(.custom("Montserrat-Medium", fixedSize: 17)) @@ -27,7 +28,7 @@ struct ScheduleGroupSettings: View { .foregroundColor(Color("customGray1")) .frame(height: 1) .padding(.horizontal) - NavigationLink(destination: FavVPKView(vm: vm)) { + NavigationLink(destination: FavVPKView(vm: vm, networkMonitor: networkMonitor)) { HStack { Text("ВПК") .font(.custom("Montserrat-Medium", fixedSize: 17)) diff --git a/Schedule ICTIS/Settings/SelectingGroupView.swift b/Schedule ICTIS/Settings/SelectingGroupView.swift index 55b0308..b7fc337 100644 --- a/Schedule ICTIS/Settings/SelectingGroupView.swift +++ b/Schedule ICTIS/Settings/SelectingGroupView.swift @@ -12,6 +12,7 @@ struct SelectingGroupView: View { @FocusState private var isFocused: Bool @State private var text: String = "" @ObservedObject var vm: ScheduleViewModel + @ObservedObject var networkMonitor: NetworkMonitor @State private var isLoading = false @State private var searchTask: DispatchWorkItem? @StateObject private var serchGroupsVM = SearchGroupsViewModel() @@ -93,9 +94,9 @@ struct SelectingGroupView: View { ) Spacer() if isLoading { - LoadingView(isLoading: $isLoading) - } - //if isFocused { + LoadingView() + Spacer() + } else if networkMonitor.isConnected { ScrollView(.vertical, showsIndicators: true) { ForEach(serchGroupsVM.groups) { item in if item.name.starts(with: "КТ") { //Отображаем только группы(без аудиторий и преподавателей) @@ -134,7 +135,9 @@ struct SelectingGroupView: View { } } } - //} + } else { + NetworkErrorView(message: "Восстановите подключение к интернету чтобы мы смогли загрузить список групп") + } } .padding(.horizontal, 10) .background(Color("background")) @@ -146,5 +149,6 @@ struct SelectingGroupView: View { #Preview { @Previewable @StateObject var vm = ScheduleViewModel() - SelectingGroupView(vm: vm, firstFavGroup: "", secondFavGroup: "", thirdFavGroup: "") + @Previewable @StateObject var vm2 = NetworkMonitor() + SelectingGroupView(vm: vm, networkMonitor: vm2, firstFavGroup: "", secondFavGroup: "", thirdFavGroup: "") } diff --git a/Schedule ICTIS/Settings/SelectingVPKView.swift b/Schedule ICTIS/Settings/SelectingVPKView.swift index 7834406..4345a01 100644 --- a/Schedule ICTIS/Settings/SelectingVPKView.swift +++ b/Schedule ICTIS/Settings/SelectingVPKView.swift @@ -12,6 +12,7 @@ struct SelectingVPKView: View { @FocusState private var isFocused: Bool @State private var text: String = "" @ObservedObject var vm: ScheduleViewModel + @ObservedObject var networkMonitor: NetworkMonitor @State private var isLoading = false @State private var searchTask: DispatchWorkItem? @StateObject private var serchGroupsVM = SearchGroupsViewModel() @@ -94,9 +95,13 @@ struct SelectingVPKView: View { ) Spacer() if isLoading { - LoadingView(isLoading: $isLoading) + LoadingView() + Spacer() + } else if networkMonitor.isConnected { + ListOfGroupsView(vm: vm, serchGroupsVM: serchGroupsVM, firstFavVPK: firstFavVPK, secondFavVPK: secondFavVPK, thirdFavVPK: thirdFavVPK) + } else { + ConnectingToNetworkView() } - ListOfGroupsView(vm: vm, serchGroupsVM: serchGroupsVM, firstFavVPK: firstFavVPK, secondFavVPK: secondFavVPK, thirdFavVPK: thirdFavVPK) } .padding(.horizontal, 10) .background(Color("background")) @@ -108,5 +113,6 @@ struct SelectingVPKView: View { #Preview { @Previewable @StateObject var vm = ScheduleViewModel() - SelectingVPKView(vm: vm, firstFavVPK: "", secondFavVPK: "", thirdFavVPK: "") + @Previewable @StateObject var vm2 = NetworkMonitor() + SelectingVPKView(vm: vm, networkMonitor: vm2, firstFavVPK: "", secondFavVPK: "", thirdFavVPK: "") } diff --git a/Schedule ICTIS/Settings/SettingsView.swift b/Schedule ICTIS/Settings/SettingsView.swift index b88a453..167f34d 100644 --- a/Schedule ICTIS/Settings/SettingsView.swift +++ b/Schedule ICTIS/Settings/SettingsView.swift @@ -9,6 +9,7 @@ import SwiftUI struct SettingsView: View { @ObservedObject var vm: ScheduleViewModel + @ObservedObject var networkMonitor: NetworkMonitor @State private var selectedTheme = "Светлая" @State private var selectedLanguage = "Русский" var body: some View { @@ -28,7 +29,7 @@ struct SettingsView: View { .font(.custom("Montserrat-Medium", fixedSize: 18)) .foregroundColor(Color("customGray3")) .padding(.horizontal) - ScheduleGroupSettings(vm: vm) + ScheduleGroupSettings(vm: vm, networkMonitor: networkMonitor) } .padding(.top, 20) } @@ -42,5 +43,6 @@ struct SettingsView: View { #Preview { @Previewable @StateObject var vm = ScheduleViewModel() - SettingsView(vm: vm) + @Previewable @StateObject var vm2 = NetworkMonitor() + SettingsView(vm: vm, networkMonitor: vm2) } diff --git a/Schedule ICTIS/TabBar/TabBarView.swift b/Schedule ICTIS/TabBar/TabBarView.swift index c47a758..2786934 100644 --- a/Schedule ICTIS/TabBar/TabBarView.swift +++ b/Schedule ICTIS/TabBar/TabBarView.swift @@ -2,14 +2,14 @@ // CustomTabBarView.swift // Schedule ICTIS // -// Created by Egor Mironov on 13.11.2024. +// Created by Mironov Egor on 13.11.2024. // import SwiftUI struct TabBarView: View { @Binding var selectedTab: TabBarModel -// @NameSpace private var animation + @Namespace private var animation var body: some View { VStack { Spacer() @@ -20,14 +20,14 @@ struct TabBarView: View { .padding(6) .background(.white) .mask(RoundedRectangle(cornerRadius: 24, style: .continuous)) - .shadow(color: .black.opacity(0.2), radius: 8, x: 4, y: 4) + .shadow(color: .black.opacity(0.4), radius: 20, x: 8, y: 8) - // .background( - // background - // .shadow(.drop(color: .black.opacity(0.08), radius: 5, x: 5, y: 5)) - // .shadow(.drop(color: .black.opacity(0.08), radius: 5, x: 5, y: -5)), - // in: .capsule - // ) + //.background( + // background + // .shadow(.drop(color: Color.black.opacity(0.08), radius: 5, x: 5, y: 5)) + // .shadow(.drop(color: Color.black.opacity(0.08), radius: 5, x: 5, y: -5)), + // in: .capsule + //) } .ignoresSafeArea(.keyboard, edges: .bottom) // Фиксаци таб-бара, при появлении клавиатуры } @@ -40,6 +40,7 @@ struct TabBarView: View { VStack (alignment: .center) { Image(systemName: tab.rawValue) .font(.title3) + .fontWeight(.regular) } .frame(width: 70, height: 28) .foregroundStyle(selectedTab == tab ? Color.white : Color("blueColor")) @@ -49,8 +50,18 @@ struct TabBarView: View { .background { if selectedTab == tab { Capsule() - .fill(Color("blueColor")) -// .matchedGeometryEffect(id: "ACTIVETAB", in: animation) + .fill( + LinearGradient( + gradient: Gradient(stops: [ + .init(color: Color("blueColor").opacity(0.9), location: 0.0), + .init(color: Color("blueColor").opacity(0.9), location: 0.5), + .init(color: Color("blueColor").opacity(1.0), location: 1.0) + ]), + startPoint: .top, + endPoint: .bottom + ) + ) + .matchedGeometryEffect(id: "ACTIVETAB", in: animation) } } }