diff --git a/Schedule ICTIS/ContentView.swift b/Schedule ICTIS/ContentView.swift index 275b738..b141d9a 100644 --- a/Schedule ICTIS/ContentView.swift +++ b/Schedule ICTIS/ContentView.swift @@ -27,7 +27,7 @@ struct ContentView: View { } .tag(1) - Text("Settings") + SettingsView(vm: vm) .tabItem { Image(systemName: "gear") Text("Настройки") @@ -35,6 +35,13 @@ struct ContentView: View { .tag(2) } .accentColor(Color("blueColor")) + .onAppear { + let group = UserDefaults.standard.string(forKey: "group") + if let nameGroup = group { + vm.group = nameGroup + vm.fetchWeekSchedule(group: nameGroup) + } + } } } diff --git a/Schedule ICTIS/Main/Views/MainView.swift b/Schedule ICTIS/Main/Views/MainView.swift index 31e8755..698c965 100644 --- a/Schedule ICTIS/Main/Views/MainView.swift +++ b/Schedule ICTIS/Main/Views/MainView.swift @@ -22,15 +22,11 @@ struct MainView: View { isFocusedSearchBar = false } } - - if (vm.isFirstStartOffApp && vm.isLoading) { + CurrentDateView() + if vm.isLoading { LoadingView(isLoading: $vm.isLoading) } - else if (vm.isFirstStartOffApp) { - FirstLaunchScheduleView() - } else { - CurrentDateView() ScheduleView(vm: vm, isScrolling: $isScrolling) } } @@ -43,6 +39,12 @@ struct MainView: View { .onTapGesture { isFocusedSearchBar = false } + .onAppear { + vm.group = UserDefaults.standard.string(forKey: "group") ?? "notSeted" + if vm.group != "notSeted" { + + } + } } @ViewBuilder diff --git a/Schedule ICTIS/Main/Views/ScheduleView.swift b/Schedule ICTIS/Main/Views/ScheduleView.swift index c263b06..21e9d3e 100644 --- a/Schedule ICTIS/Main/Views/ScheduleView.swift +++ b/Schedule ICTIS/Main/Views/ScheduleView.swift @@ -11,6 +11,8 @@ struct ScheduleView: View { @ObservedObject var vm: ScheduleViewModel @FetchRequest(fetchRequest: ClassModel.all()) private var classes //Делаем запрос в CoreData и получаем список сохраненных пар @State private var selectedClass: ClassModel? = nil + @State private var lastOffset: CGFloat = 0 + @State private var scrollTimer: Timer? = nil @Binding var isScrolling: Bool var provider = ClassProvider.shared var body: some View { @@ -73,17 +75,28 @@ struct ScheduleView: View { .frame(width: UIScreen.main.bounds.width) .padding(.bottom, 100) .padding(.top, 30) + .background(GeometryReader { geometry in + Color.clear.preference(key: ViewOffsetKey.self, value: geometry.frame(in: .global).minY) + }) } .onPreferenceChange(ViewOffsetKey.self) { offset in - if offset > 0 { + if offset != lastOffset { + // Скролл происходит isScrolling = true - print("Сейчас скролл") - } else { - isScrolling = false - print("Scrolling ended") + + // Останавливаем предыдущий таймер + scrollTimer?.invalidate() + // Запускаем новый таймер + scrollTimer = Timer.scheduledTimer(withTimeInterval: 0.1, repeats: false) { _ in + // Скролл остановился + isScrolling = false + } } + lastOffset = offset + } + .onDisappear { + scrollTimer?.invalidate() } - .coordinateSpace(name: "scroll") VStack { LinearGradient(gradient: Gradient(colors: [Color("background").opacity(0.95), Color.white.opacity(0.1)]), startPoint: .top, endPoint: .bottom) } diff --git a/Schedule ICTIS/Main/Views/SearchBarView.swift b/Schedule ICTIS/Main/Views/SearchBarView.swift index cafa5be..569d458 100644 --- a/Schedule ICTIS/Main/Views/SearchBarView.swift +++ b/Schedule ICTIS/Main/Views/SearchBarView.swift @@ -38,7 +38,6 @@ struct SearchBarView: View { Button { self.text = "" self.isFocused = false - UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil) } label: { Image(systemName: "xmark.circle.fill") .padding(.trailing, 20) diff --git a/Schedule ICTIS/Main/Views/TabViews/MonthTabView.swift b/Schedule ICTIS/Main/Views/TabViews/MonthTabView.swift index 8fe0419..3b3c652 100644 --- a/Schedule ICTIS/Main/Views/TabViews/MonthTabView.swift +++ b/Schedule ICTIS/Main/Views/TabViews/MonthTabView.swift @@ -8,8 +8,8 @@ import SwiftUI struct MonthTabView: View { - @State private var currentMonthIndex: Int = 1 - @State private var monthSlider: [[Date.MonthWeek]] = [] + @State var currentMonthIndex: Int = 1 + @State var monthSlider: [[Date.MonthWeek]] = [] @State private var createMonth: Bool = false @State private var currentWeekIndex: Int = 0 @ObservedObject var vm: ScheduleViewModel @@ -79,53 +79,8 @@ struct MonthTabView: View { } } } - - func paginateMonth(_ indexOfWeek: Int = 0) { - let calendar = Calendar.current - if monthSlider.indices.contains(currentMonthIndex) { - if let firstDate = monthSlider[currentMonthIndex].first?.week[0].date, - currentMonthIndex == 0 { - monthSlider.insert(firstDate.createPreviousMonth(), at: 0) - monthSlider.removeLast() - currentMonthIndex = 1 - vm.selectedDay = calendar.date(byAdding: .weekOfYear, value: -5, to: vm.selectedDay) ?? Date.init() - vm.updateSelectedDayIndex() - vm.week -= 5 - vm.fetchWeekSchedule(isOtherWeek: true) - } - - if let lastDate = monthSlider[currentMonthIndex].last?.week[6].date, - currentMonthIndex == (monthSlider.count - 1) { - monthSlider.append(lastDate.createNextMonth()) - monthSlider.removeFirst() - currentMonthIndex = monthSlider.count - 2 - vm.selectedDay = calendar.date(byAdding: .weekOfYear, value: 5, to: vm.selectedDay) ?? Date.init() - vm.updateSelectedDayIndex() - vm.week += 5 - vm.fetchWeekSchedule(isOtherWeek: true) - } - } - } } -extension MonthTabView { - func updateMonthScreenViewForNewGroup() { - vm.updateSelectedDayIndex() - if monthSlider.isEmpty { - let currentMonth = Date().fetchMonth(vm.selectedDay) - - if let firstDate = currentMonth.first?.week[0].date { - monthSlider.append(firstDate.createPreviousMonth()) - } - - monthSlider.append(currentMonth) - - if let lastDate = currentMonth.last?.week[6].date { - monthSlider.append(lastDate.createNextMonth()) - } - } - } -} #Preview { ContentView() diff --git a/Schedule ICTIS/Main/Views/TabViews/WeekTabView.swift b/Schedule ICTIS/Main/Views/TabViews/WeekTabView.swift index 9308fe5..da58428 100644 --- a/Schedule ICTIS/Main/Views/TabViews/WeekTabView.swift +++ b/Schedule ICTIS/Main/Views/TabViews/WeekTabView.swift @@ -9,7 +9,7 @@ import SwiftUI struct WeekTabView: View { @State private var currentWeekIndex: Int = 1 - @State private var weekSlider: [[Date.WeekDay]] = [] + @State var weekSlider: [[Date.WeekDay]] = [] @State private var createWeek: Bool = false @ObservedObject var vm: ScheduleViewModel var body: some View { @@ -45,25 +45,6 @@ struct WeekTabView: View { } } -extension WeekTabView { - func updateWeekScreenViewForNewGroup() { - vm.updateSelectedDayIndex() - if weekSlider.isEmpty { - let currentWeek = Date().fetchWeek(vm.selectedDay) - - if let firstDate = currentWeek.first?.date { - weekSlider.append(firstDate.createPrevioustWeek()) - } - - weekSlider.append(currentWeek) - - if let lastDate = currentWeek.last?.date { - weekSlider.append(lastDate.createNextWeek()) - } - } - } -} - #Preview { ContentView() } diff --git a/Schedule ICTIS/Main/Views/TabViews/WeekViewForMonth.swift b/Schedule ICTIS/Main/Views/TabViews/WeekViewForMonth.swift index 4179b49..a06c29b 100644 --- a/Schedule ICTIS/Main/Views/TabViews/WeekViewForMonth.swift +++ b/Schedule ICTIS/Main/Views/TabViews/WeekViewForMonth.swift @@ -29,42 +29,4 @@ struct WeekViewForMonth: View { } } } - - private func getForegroundColor(day: Date.WeekDay) -> Color { - if isDateInCurrentMonth(day.date) { - return isSameDate(day.date, vm.selectedDay) ? .white : .black - } else { - return isSameDate(day.date, vm.selectedDay) ? .white : Color("greyForDaysInMonthTabView") - } - } - - private func getBackgroundColor(day: Date.WeekDay) -> Color { - return isSameDate(day.date, vm.selectedDay) ? Color("blueColor") : Color("background") - } - - private func overlay(day: Date.WeekDay) -> some View { - Group { - if day.date.isToday && !isSameDate(day.date, vm.selectedDay) { - RoundedRectangle(cornerRadius: 100) - .stroke(Color("blueColor"), lineWidth: 2) - } - } - } - - private func handleTap(day: Date.WeekDay) { - if isSameWeek(day.date, vm.selectedDay) { - print("На одной неделе") - } - else { - var difBetweenWeeks = weeksBetween(startDate: vm.selectedDay, endDate: day.date) - if day.date < vm.selectedDay { - difBetweenWeeks = difBetweenWeeks * -1 - } - print(difBetweenWeeks) - vm.week += difBetweenWeeks - vm.fetchWeekSchedule(isOtherWeek: true) - } - vm.selectedDay = day.date - vm.updateSelectedDayIndex() - } } diff --git a/Schedule ICTIS/Main/Views/TabViews/WeekViewForWeek.swift b/Schedule ICTIS/Main/Views/TabViews/WeekViewForWeek.swift index 648bab4..49f6b54 100644 --- a/Schedule ICTIS/Main/Views/TabViews/WeekViewForWeek.swift +++ b/Schedule ICTIS/Main/Views/TabViews/WeekViewForWeek.swift @@ -73,30 +73,4 @@ struct WeekViewForWeek: View { } } } - func paginateWeek() { - let calendar = Calendar.current - if weekSlider.indices.contains(currentWeekIndex) { - if let firstDate = weekSlider[currentWeekIndex].first?.date, - currentWeekIndex == 0 { - vm.week -= 1 - vm.fetchWeekSchedule(isOtherWeek: true) - weekSlider.insert(firstDate.createPrevioustWeek(), at: 0) - weekSlider.removeLast() - currentWeekIndex = 1 - vm.selectedDay = calendar.date(byAdding: .weekOfYear, value: -1, to: vm.selectedDay) ?? Date.init() - vm.updateSelectedDayIndex() - } - - if let lastDate = weekSlider[currentWeekIndex].last?.date, - currentWeekIndex == (weekSlider.count - 1) { - vm.week += 1 - vm.fetchWeekSchedule(isOtherWeek: true) - weekSlider.append(lastDate.createNextWeek()) - weekSlider.removeFirst() - currentWeekIndex = weekSlider.count - 2 - vm.selectedDay = calendar.date(byAdding: .weekOfYear, value: 1, to: vm.selectedDay) ?? Date.init() - vm.updateSelectedDayIndex() - } - } - } } diff --git a/Schedule ICTIS/MockData.swift b/Schedule ICTIS/MockData.swift index 602d106..80f9783 100644 --- a/Schedule ICTIS/MockData.swift +++ b/Schedule ICTIS/MockData.swift @@ -15,4 +15,8 @@ struct MockData { static let notifications = ["Нет", "За 10 минут", "За 30 миннут", "За 1 час"] static let onlineOrOffline = ["Оффлайн", "Онлайн"] + + static let themes = ["Светлая", "Темная", "Системная"] + + static let languages = ["Русский", "Английский", "Китайский", "Испанский"] } diff --git a/Schedule ICTIS/Preview Content/Assets.xcassets/arrowRight.imageset/Contents.json b/Schedule ICTIS/Preview Content/Assets.xcassets/arrowRight.imageset/Contents.json new file mode 100644 index 0000000..985ff81 --- /dev/null +++ b/Schedule ICTIS/Preview Content/Assets.xcassets/arrowRight.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "arrowRight.svg", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Schedule ICTIS/Preview Content/Assets.xcassets/arrowRight.imageset/arrowRight.svg b/Schedule ICTIS/Preview Content/Assets.xcassets/arrowRight.imageset/arrowRight.svg new file mode 100644 index 0000000..394cec0 --- /dev/null +++ b/Schedule ICTIS/Preview Content/Assets.xcassets/arrowRight.imageset/arrowRight.svg @@ -0,0 +1,3 @@ + + + diff --git a/Schedule ICTIS/Settings/SelectingGroupView.swift b/Schedule ICTIS/Settings/SelectingGroupView.swift new file mode 100644 index 0000000..ad4923b --- /dev/null +++ b/Schedule ICTIS/Settings/SelectingGroupView.swift @@ -0,0 +1,68 @@ +// +// SelectedGroupView.swift +// Schedule ICTIS +// +// Created by G412 on 30.01.2025. +// + +import SwiftUI + +struct SelectingGroupView: View { + @Environment(\.dismiss) private var dismiss + @FocusState private var isFocused: Bool + @State private var text: String = "" + @Binding var group: String + var body: some View { + NavigationView { + VStack { + HStack (spacing: 0) { + Image(systemName: "magnifyingglass") + .foregroundColor(Color.gray) + .padding(.leading, 12) + .padding(.trailing, 7) + TextField("Поиск группы", text: $text) + .disableAutocorrection(true) + .focused($isFocused) + .onSubmit { + self.isFocused = false + if (!text.isEmpty) { + UserDefaults.standard.set(text, forKey: "group") + group = text + } + self.text = "" + dismiss() + } + .submitLabel(.done) + if isFocused { + Button { + self.text = "" + self.isFocused = false + } label: { + Image(systemName: "xmark.circle.fill") + .padding(.trailing, 20) + .offset(x: 10) + .foregroundColor(.gray) + .background( + ) + } + } + } + .frame(height: 40) + .background( + RoundedRectangle(cornerRadius: 15) + .fill(.white) + ) + .padding(.horizontal, 10) + Spacer() + } + .background(Color("background")) + .onTapGesture { + self.isFocused = false + } + } + } +} + +#Preview { + SelectingGroupView(group: .constant("КТбо2-6")) +} diff --git a/Schedule ICTIS/Settings/SelectingVPKView.swift b/Schedule ICTIS/Settings/SelectingVPKView.swift new file mode 100644 index 0000000..fe40657 --- /dev/null +++ b/Schedule ICTIS/Settings/SelectingVPKView.swift @@ -0,0 +1,64 @@ +// +// SelectedVPKView.swift +// Schedule ICTIS +// +// Created by G412 on 30.01.2025. +// + +import SwiftUI + +struct SelectingVPKView: View { + @FocusState private var isFocused: Bool + @State private var text: String = "" + var body: some View { + NavigationView { + VStack { + HStack (spacing: 0) { + Image(systemName: "magnifyingglass") + .foregroundColor(Color.gray) + .padding(.leading, 12) + .padding(.trailing, 7) + TextField("Поиск ВПК", text: $text) + .disableAutocorrection(true) + .focused($isFocused) + .onSubmit { + self.isFocused = false + if (!text.isEmpty) { + UserDefaults.standard.set(text, forKey: "group") + } + self.text = "" + } + .submitLabel(.done) + if isFocused { + Button { + self.text = "" + self.isFocused = false + } label: { + Image(systemName: "xmark.circle.fill") + .padding(.trailing, 20) + .offset(x: 10) + .foregroundColor(.gray) + .background( + ) + } + } + } + .frame(height: 40) + .background( + RoundedRectangle(cornerRadius: 15) + .fill(.white) + ) + .padding(.horizontal, 10) + Spacer() + } + .background(Color("background")) + .onTapGesture { + self.isFocused = false + } + } + } +} + +#Preview { + SelectingVPKView() +} diff --git a/Schedule ICTIS/Settings/SettingsView.swift b/Schedule ICTIS/Settings/SettingsView.swift new file mode 100644 index 0000000..4d6f60f --- /dev/null +++ b/Schedule ICTIS/Settings/SettingsView.swift @@ -0,0 +1,55 @@ +// +// SettingsView.swift +// Schedule ICTIS +// +// Created by G412 on 30.01.2025. +// + +import SwiftUI + +struct SettingsView: View { + @ObservedObject var vm: ScheduleViewModel + @State private var selectedTheme = "Светлая" + @State private var selectedLanguage = "Русский" + var body: some View { + NavigationView { + VStack { + List { + Section("Общие") { + Picker("Тема", selection: $selectedTheme, content: { + ForEach(MockData.themes, id: \.self) { + Text($0) + } + }) + Picker("Язык", selection: $selectedLanguage, content: { + ForEach(MockData.languages, id: \.self) { + Text($0) + } + }) + } + Section("Расписание") { + NavigationLink(destination: SelectingGroupView(group: $vm.group)) { + LabeledContent { + Text(vm.group) + } label: { + Text("Избранное расписание") + } + } + NavigationLink(destination: SelectingVPKView()) { + LabeledContent { + } label: { + Text("ВПК") + } + } + } + } + } + .navigationTitle("Настройки") + } + } +} + +#Preview { + @Previewable @StateObject var vm = ScheduleViewModel() + SettingsView(vm: vm) +} diff --git a/Schedule ICTIS/Main/Views/TabBar/TabBarView.swift b/Schedule ICTIS/TabBar/TabBarView.swift similarity index 100% rename from Schedule ICTIS/Main/Views/TabBar/TabBarView.swift rename to Schedule ICTIS/TabBar/TabBarView.swift diff --git a/Schedule ICTIS/Utilities/Extensions/View+Extensions.swift b/Schedule ICTIS/Utilities/Extensions/View+Extensions.swift index 889c578..a1540d5 100644 --- a/Schedule ICTIS/Utilities/Extensions/View+Extensions.swift +++ b/Schedule ICTIS/Utilities/Extensions/View+Extensions.swift @@ -160,3 +160,137 @@ extension View { } } } + +extension WeekTabView { + func updateWeekScreenViewForNewGroup() { + vm.updateSelectedDayIndex() + if weekSlider.isEmpty { + let currentWeek = Date().fetchWeek(vm.selectedDay) + + if let firstDate = currentWeek.first?.date { + weekSlider.append(firstDate.createPrevioustWeek()) + } + + weekSlider.append(currentWeek) + + if let lastDate = currentWeek.last?.date { + weekSlider.append(lastDate.createNextWeek()) + } + } + } +} + +extension WeekViewForWeek { + func paginateWeek() { + let calendar = Calendar.current + if weekSlider.indices.contains(currentWeekIndex) { + if let firstDate = weekSlider[currentWeekIndex].first?.date, + currentWeekIndex == 0 { + vm.week -= 1 + vm.fetchWeekSchedule(isOtherWeek: true) + weekSlider.insert(firstDate.createPrevioustWeek(), at: 0) + weekSlider.removeLast() + currentWeekIndex = 1 + vm.selectedDay = calendar.date(byAdding: .weekOfYear, value: -1, to: vm.selectedDay) ?? Date.init() + vm.updateSelectedDayIndex() + } + + if let lastDate = weekSlider[currentWeekIndex].last?.date, + currentWeekIndex == (weekSlider.count - 1) { + vm.week += 1 + vm.fetchWeekSchedule(isOtherWeek: true) + weekSlider.append(lastDate.createNextWeek()) + weekSlider.removeFirst() + currentWeekIndex = weekSlider.count - 2 + vm.selectedDay = calendar.date(byAdding: .weekOfYear, value: 1, to: vm.selectedDay) ?? Date.init() + vm.updateSelectedDayIndex() + } + } + } +} + +extension WeekViewForMonth { + func getForegroundColor(day: Date.WeekDay) -> Color { + if isDateInCurrentMonth(day.date) { + return isSameDate(day.date, vm.selectedDay) ? .white : .black + } else { + return isSameDate(day.date, vm.selectedDay) ? .white : Color("greyForDaysInMonthTabView") + } + } + + func getBackgroundColor(day: Date.WeekDay) -> Color { + return isSameDate(day.date, vm.selectedDay) ? Color("blueColor") : Color("background") + } + + func overlay(day: Date.WeekDay) -> some View { + Group { + if day.date.isToday && !isSameDate(day.date, vm.selectedDay) { + RoundedRectangle(cornerRadius: 100) + .stroke(Color("blueColor"), lineWidth: 2) + } + } + } + + func handleTap(day: Date.WeekDay) { + if isSameWeek(day.date, vm.selectedDay) { + print("На одной неделе") + } + else { + var difBetweenWeeks = weeksBetween(startDate: vm.selectedDay, endDate: day.date) + if day.date < vm.selectedDay { + difBetweenWeeks = difBetweenWeeks * -1 + } + print(difBetweenWeeks) + vm.week += difBetweenWeeks + vm.fetchWeekSchedule(isOtherWeek: true) + } + vm.selectedDay = day.date + vm.updateSelectedDayIndex() + } +} + +extension MonthTabView { + func updateMonthScreenViewForNewGroup() { + vm.updateSelectedDayIndex() + if monthSlider.isEmpty { + let currentMonth = Date().fetchMonth(vm.selectedDay) + + if let firstDate = currentMonth.first?.week[0].date { + monthSlider.append(firstDate.createPreviousMonth()) + } + + monthSlider.append(currentMonth) + + if let lastDate = currentMonth.last?.week[6].date { + monthSlider.append(lastDate.createNextMonth()) + } + } + } + + func paginateMonth(_ indexOfWeek: Int = 0) { + let calendar = Calendar.current + if monthSlider.indices.contains(currentMonthIndex) { + if let firstDate = monthSlider[currentMonthIndex].first?.week[0].date, + currentMonthIndex == 0 { + monthSlider.insert(firstDate.createPreviousMonth(), at: 0) + monthSlider.removeLast() + currentMonthIndex = 1 + vm.selectedDay = calendar.date(byAdding: .weekOfYear, value: -5, to: vm.selectedDay) ?? Date.init() + vm.updateSelectedDayIndex() + vm.week -= 5 + vm.fetchWeekSchedule(isOtherWeek: true) + } + + if let lastDate = monthSlider[currentMonthIndex].last?.week[6].date, + currentMonthIndex == (monthSlider.count - 1) { + monthSlider.append(lastDate.createNextMonth()) + monthSlider.removeFirst() + currentMonthIndex = monthSlider.count - 2 + vm.selectedDay = calendar.date(byAdding: .weekOfYear, value: 5, to: vm.selectedDay) ?? Date.init() + vm.updateSelectedDayIndex() + vm.week += 5 + vm.fetchWeekSchedule(isOtherWeek: true) + } + } + } +} diff --git a/Schedule ICTIS/ViewModel/ScheduleViewModel.swift b/Schedule ICTIS/ViewModel/ScheduleViewModel.swift index 83c6805..f9442ca 100644 --- a/Schedule ICTIS/ViewModel/ScheduleViewModel.swift +++ b/Schedule ICTIS/ViewModel/ScheduleViewModel.swift @@ -36,11 +36,11 @@ final class ScheduleViewModel: ObservableObject { Task { do { var schedule: Schedule - // В этот if мы заходим только если пользователь перелистывает недели и нам известы номер группы(в html формате) и номер неделе, которая показывается пользователю + // В этот if мы заходим только если пользователь перелистывает недели и нам известы номер группы(в html формате) и номер недели, которая показывается пользователю if (isOtherWeek || !isFirstStartOffApp) && (group == "default") { schedule = try await NetworkManager.shared.getScheduleForOtherWeek(self.week, self.numOfGroup) } - // В else мы заходим в том случае, если не знаем номера недели, которую нужно отобразить и номер группы(в html формате) + // В else мы заходим в том случае, если не знаем номер недели, которую нужно отобразить и номер группы(в html формате) else { schedule = try await NetworkManager.shared.getSchedule(group) if (!self.isFirstStartOffApp) {