diff --git a/Schedule ICTIS/Main/Views/CreatedClassView.swift b/Schedule ICTIS/Main/Views/CreatedClassView.swift new file mode 100644 index 0000000..c490534 --- /dev/null +++ b/Schedule ICTIS/Main/Views/CreatedClassView.swift @@ -0,0 +1,46 @@ +// +// CreatedClassView.swift +// Schedule ICTIS +// +// Created by G412 on 23.12.2024. +// + +import SwiftUI + +struct CreatedClassView: View { + let _class: ClassModel + var body: some View { + if datesAreEqual(_class.day, ClassModel.dateNow) { + HStack(spacing: 10) { + VStack { + Text(getTimeString(_class.starttime)) + .font(.system(size: 15, weight: .regular)) + Text(getTimeString(_class.endtime)) + .font(.system(size: 15, weight: .regular)) + } + .padding(.top, 7) + .padding(.bottom, 7) + .padding(.leading, 10) + Rectangle() + .frame(width: 2) + .frame(maxHeight: UIScreen.main.bounds.height - 18) + .padding(.top, 7) + .padding(.bottom, 7) + .foregroundColor(_class.important ? Color("redForImportant") : onlineOrNot(_class.online)) + Text(getSubjectName(_class.subject, _class.professor, _class.auditory)) + .font(.system(size: 18, weight: .regular)) + .padding(.top, 7) + .padding(.bottom, 7) + Spacer() + } + .frame(maxWidth: UIScreen.main.bounds.width - 40, maxHeight: 230) + .background(Color.white) + .cornerRadius(20) + .shadow(color: .black.opacity(0.25), radius: 4, x: 2, y: 2) + } + } +} + +#Preview { + CreatedClassView(_class: .preview()) +} diff --git a/Schedule ICTIS/Main/Views/Fields/StartEndTimeFieldView.swift b/Schedule ICTIS/Main/Views/Fields/StartEndTimeFieldView.swift index 61c55c2..7ec4063 100644 --- a/Schedule ICTIS/Main/Views/Fields/StartEndTimeFieldView.swift +++ b/Schedule ICTIS/Main/Views/Fields/StartEndTimeFieldView.swift @@ -8,6 +8,8 @@ import SwiftUI struct StartEndTimeFieldView: View { + @Binding var isIncorrectDate: Bool + @Binding var selectedDay: Date @Binding var selectedTime: Date var imageName: String var text: String @@ -15,7 +17,7 @@ struct StartEndTimeFieldView: View { var body: some View { HStack { Image(systemName: imageName) - .foregroundColor(Color("grayForFields")) + .foregroundColor(isIncorrectDate ? .red : Color("grayForFields")) .padding(.leading, 12) if !isTimeSelected { @@ -26,7 +28,7 @@ struct StartEndTimeFieldView: View { if isTimeSelected { Text("\(selectedTime, formatter: timeFormatter)") - .foregroundColor(.black) + .foregroundColor(isIncorrectDate ? .red : .black) .font(.system(size: 17, weight: .medium)) .padding(.trailing, 10) } @@ -38,16 +40,22 @@ struct StartEndTimeFieldView: View { .fill(.white) ) .overlay { - DatePicker("", selection: $selectedTime, in: Date()..., displayedComponents: .hourAndMinute) - .padding(.trailing, 35) - .blendMode(.destinationOver) - .onChange(of: selectedTime) { newValue, oldValue in - isTimeSelected = true - } + if isSameDate(selectedTime, selectedDay) { + DatePicker("", selection: $selectedTime, in: Date()..., displayedComponents: .hourAndMinute) + .padding(.trailing, 35) + .blendMode(.destinationOver) + .onChange(of: selectedTime) { newValue, oldValue in + isTimeSelected = true + } + } + else { + DatePicker("", selection: $selectedTime, displayedComponents: .hourAndMinute) + .padding(.trailing, 35) + .blendMode(.destinationOver) + .onChange(of: selectedTime) { newValue, oldValue in + isTimeSelected = true + } + } } } } - -#Preview { - StartEndTimeFieldView(selectedTime: .constant(Date()), imageName: "clock", text: "Начало") -} diff --git a/Schedule ICTIS/Main/Views/ScheduleView.swift b/Schedule ICTIS/Main/Views/ScheduleView.swift index faf0d83..78ab6aa 100644 --- a/Schedule ICTIS/Main/Views/ScheduleView.swift +++ b/Schedule ICTIS/Main/Views/ScheduleView.swift @@ -2,15 +2,16 @@ // ScheduleView.swift // Schedule ICTIS // -// Created by G412 on 05.12.2024. +// Created by Mironov Egor on 05.12.2024. // import SwiftUI struct ScheduleView: View { - @State private var isShowingSheet: Bool = false @ObservedObject var vm: ScheduleViewModel @FetchRequest(fetchRequest: ClassModel.all()) private var classes + @State private var isShowingEditClassView = false + @State private var selectedClass: ClassModel? = nil var body: some View { if vm.isLoading { LoadingView(isLoading: $vm.isLoading) @@ -52,45 +53,16 @@ struct ScheduleView: View { .background(Color.white) .cornerRadius(20) .shadow(color: .black.opacity(0.25), radius: 4, x: 2, y: 2) - .onTapGesture { - isShowingSheet = true - } } } } } ForEach(classes) { _class in - if datesAreEqual(_class.day, vm.selectedDay) { - HStack(spacing: 10) { - VStack { - Text(getTimeString(_class.starttime)) - .font(.system(size: 15, weight: .regular)) - Text(getTimeString(_class.endtime)) - .font(.system(size: 15, weight: .regular)) - } - .padding(.top, 7) - .padding(.bottom, 7) - .padding(.leading, 10) - Rectangle() - .frame(width: 2) - .frame(maxHeight: UIScreen.main.bounds.height - 18) - .padding(.top, 7) - .padding(.bottom, 7) - .foregroundColor(_class.important ? Color("redForImportant") : onlineOrNot(_class.online)) - Text(getSubjectName(_class.subject, _class.professor, _class.auditory)) - .font(.system(size: 18, weight: .regular)) - .padding(.top, 7) - .padding(.bottom, 7) - Spacer() - } - .frame(maxWidth: UIScreen.main.bounds.width - 40, maxHeight: 230) - .background(Color.white) - .cornerRadius(20) - .shadow(color: .black.opacity(0.25), radius: 4, x: 2, y: 2) + CreatedClassView(_class: _class) .onTapGesture { - isShowingSheet = true + isShowingEditClassView = true + selectedClass = _class } - } } } .frame(width: UIScreen.main.bounds.width) @@ -102,14 +74,17 @@ struct ScheduleView: View { } .frame(width: UIScreen.main.bounds.width, height: 15) } - .sheet(isPresented: $isShowingSheet) { - SheetChangeClassView(isShowingSheet: $isShowingSheet) + .sheet(isPresented: $isShowingEditClassView) { + if let selectedClass = selectedClass { + EditClassView(isShowingSheet: $isShowingEditClassView, _class: selectedClass) + } } } else { NoScheduleView() } } + } } diff --git a/Schedule ICTIS/Main/Views/SearchBarView.swift b/Schedule ICTIS/Main/Views/SearchBarView.swift index 5cff2c7..3a6d275 100644 --- a/Schedule ICTIS/Main/Views/SearchBarView.swift +++ b/Schedule ICTIS/Main/Views/SearchBarView.swift @@ -30,9 +30,6 @@ struct SearchBarView: View { .onSubmit { self.isEditing = false if (!text.isEmpty) { - if !vm.numOfGroup.isEmpty { - - } vm.fetchWeekSchedule(text) vm.group = text } @@ -83,7 +80,7 @@ struct SearchBarView: View { .frame(height: 40) .accentColor(.blue) .sheet(isPresented: $isShowingSheet) { - SheetCreateClassView(isShowingSheet: $isShowingSheet, vm: .init(provider: provider)) + CreateClassView(isShowingSheet: $isShowingSheet, vm: .init(provider: provider)) } } } diff --git a/Schedule ICTIS/Main/Views/Sheets/SheetCreateClassView.swift b/Schedule ICTIS/Main/Views/Sheets/CreateClassView.swift similarity index 64% rename from Schedule ICTIS/Main/Views/Sheets/SheetCreateClassView.swift rename to Schedule ICTIS/Main/Views/Sheets/CreateClassView.swift index 0486619..e241272 100644 --- a/Schedule ICTIS/Main/Views/Sheets/SheetCreateClassView.swift +++ b/Schedule ICTIS/Main/Views/Sheets/CreateClassView.swift @@ -7,17 +7,12 @@ import SwiftUI -struct SheetCreateClassView: View { +struct CreateClassView: View { @Binding var isShowingSheet: Bool - @State private var textForNameOfClass = "" - @State private var textForNameOfAuditory = "" - @State private var textForNameOfProfessor = "" @State private var isShowingDatePickerForDate: Bool = false - @State private var isImportant: Bool = false - @State private var selectedOptionForNotification: String = "Нет" - @State private var selectedOptionForOnline: String = "Оффлайн" - @State private var textForComment: String = "" @ObservedObject var vm: EditClassViewModel + @State private var isIncorrectDate1: Bool = false + @State private var isIncorrectDate2: Bool = false var body: some View { NavigationView { @@ -54,20 +49,42 @@ struct SheetCreateClassView: View { } .padding(.bottom, 10) HStack { - StartEndTimeFieldView(selectedTime: $vm._class.starttime, imageName: "clock", text: "Начало") + StartEndTimeFieldView(isIncorrectDate: $isIncorrectDate1, selectedDay: $vm._class.day, selectedTime: $vm._class.starttime, imageName: "clock", text: "Начало") .onChange(of: vm._class.starttime) { oldValue, newValue in if !checkStartTimeLessThenEndTime(vm._class.starttime, vm._class.endtime) { - print("Values \(oldValue) - \(newValue) 1") - print(vm._class.starttime) - vm._class.starttime = oldValue + self.isIncorrectDate1 = true + } + else { + self.isIncorrectDate1 = false + self.isIncorrectDate2 = false + } + } + .overlay { + if isIncorrectDate1 { + Rectangle() + .frame(maxWidth: 300, maxHeight: 1) + .foregroundColor(.red) + .padding(.horizontal) } } Spacer() - StartEndTimeFieldView(selectedTime: $vm._class.endtime, imageName: "clock.badge.xmark", text: "Конец") + StartEndTimeFieldView(isIncorrectDate: $isIncorrectDate2, selectedDay: $vm._class.day, selectedTime: $vm._class.endtime, imageName: "clock.badge.xmark", text: "Конец") .onChange(of: vm._class.endtime) { oldValue, newValue in - print("Values \(oldValue) - \(newValue) 2") - print(vm._class.endtime) - validateTime(old: oldValue, new: newValue, isStartChanged: false) + if !checkStartTimeLessThenEndTime(vm._class.starttime, vm._class.endtime) { + self.isIncorrectDate2 = true + } + else { + self.isIncorrectDate1 = false + self.isIncorrectDate2 = false + } + } + .overlay { + if isIncorrectDate2 { + Rectangle() + .frame(maxWidth: 300, maxHeight: 1) + .foregroundColor(.red) + .padding(.horizontal) + } } } .frame(height: 40) @@ -143,18 +160,38 @@ struct SheetCreateClassView: View { .background(Color("background")) } } - func validateTime(old oldValue: Date, new newValue: Date, isStartChanged: Bool) { - if !checkStartTimeLessThenEndTime(vm._class.starttime, vm._class.endtime) { - if isStartChanged { - vm._class.starttime = Date() - } else { - vm._class.starttime = Date() + func checkStartTimeLessThenEndTime(_ startTime: Date, _ endTime: Date) -> Bool { + let calendar = Calendar.current + + let firstComponents = calendar.dateComponents([.hour, .minute], from: startTime) + let secondComponents = calendar.dateComponents([.hour, .minute], from: endTime) + + guard let startHours = firstComponents.hour, let startMinutes = firstComponents.minute else { + return false + } + guard let endHours = secondComponents.hour, let endMinutes = secondComponents.minute else { + return false + } + + print("\(startHours) - \(endHours)") + print("\(startMinutes) - \(endMinutes)") + if Int(startHours) > Int(endHours) { + return false + } + else if startHours == endHours { + if startMinutes < endMinutes { + return true } - print("Invalid time selected. Reverting to old value.") + else { + return false + } + } + else { + return true } } } #Preview { - SheetCreateClassView(isShowingSheet: .constant(true), vm: .init(provider: .shared)) + CreateClassView(isShowingSheet: .constant(true), vm: .init(provider: .shared)) } diff --git a/Schedule ICTIS/Main/Views/Sheets/EditClassView.swift b/Schedule ICTIS/Main/Views/Sheets/EditClassView.swift new file mode 100644 index 0000000..a9476dd --- /dev/null +++ b/Schedule ICTIS/Main/Views/Sheets/EditClassView.swift @@ -0,0 +1,103 @@ +// +// SheetCreateClassView.swift +// Schedule ICTIS +// +// Created by Mironov Egor on 12.12.2024. +// + +import SwiftUI + +struct EditClassView: View { + @State private var isIncorrectDate1: Bool = false + @State private var isIncorrectDate2: Bool = false + @Binding var isShowingSheet: Bool + + let _class: ClassModel + + @State private var subject: String = "" + + var body: some View { + NavigationStack { + ProfessorAuditoryClassFieldView(text: $subject, nameOfImage: "book", labelForField: "Предмет") + .padding(.bottom, 10) + List { + Section("General") { + LabeledContent { + Text(_class.subject) + } label: { + Text("Предмет") + } + + LabeledContent { + Text(_class.auditory) + } label: { + Text("Аудитория") + } + + LabeledContent { + Text(_class.day, style: .date) + } label: { + Text("Преподаватель") + } + + } + + Section("Notes") { + Text(_class.comment) + } + } + .toolbar { + ToolbarItem(placement: .navigationBarLeading) { + Button("Отменить") { + isShowingSheet = false + } + } + ToolbarItem(placement: .navigationBarTrailing) { + Button("Сохранить") { + isShowingSheet = false + } + } + } + } + .onAppear { + subject = _class.subject + } + } + + func checkStartTimeLessThenEndTime(_ startTime: Date, _ endTime: Date) -> Bool { + let calendar = Calendar.current + + let firstComponents = calendar.dateComponents([.hour, .minute], from: startTime) + let secondComponents = calendar.dateComponents([.hour, .minute], from: endTime) + + guard let startHours = firstComponents.hour, let startMinutes = firstComponents.minute else { + return false + } + guard let endHours = secondComponents.hour, let endMinutes = secondComponents.minute else { + return false + } + + print("\(startHours) - \(endHours)") + print("\(startMinutes) - \(endMinutes)") + if Int(startHours) > Int(endHours) { + return false + } + else if startHours == endHours { + if startMinutes < endMinutes { + return true + } + else { + return false + } + } + else { + return true + } + } +} + +#Preview { + NavigationStack { + EditClassView(isShowingSheet: .constant(true), _class: .preview()) + } +} diff --git a/Schedule ICTIS/Main/Views/Sheets/SheetChangeClassView.swift b/Schedule ICTIS/Main/Views/Sheets/SheetChangeClassView.swift deleted file mode 100644 index 4637177..0000000 --- a/Schedule ICTIS/Main/Views/Sheets/SheetChangeClassView.swift +++ /dev/null @@ -1,37 +0,0 @@ -// -// SheetView.swift -// Schedule ICTIS -// -// Created by Mironov Egor on 12.12.2024. -// - -import SwiftUI - -struct SheetChangeClassView: View { - @Binding var isShowingSheet: Bool - var body: some View { - NavigationView { - VStack { - Spacer() - Text("Редактирвоание пары") - Spacer() - } - .toolbar { - ToolbarItem(placement: .navigationBarLeading) { - Button("Отменить") { - isShowingSheet = false - } - } - ToolbarItem(placement: .navigationBarTrailing) { - Button("Сохранить") { - isShowingSheet = false - } - } - } - } - } -} - -#Preview { - SheetChangeClassView(isShowingSheet: .constant(true)) -} diff --git a/Schedule ICTIS/Main/Views/TabViews/MonthTabView.swift b/Schedule ICTIS/Main/Views/TabViews/MonthTabView.swift index 1ea3a12..f75608b 100644 --- a/Schedule ICTIS/Main/Views/TabViews/MonthTabView.swift +++ b/Schedule ICTIS/Main/Views/TabViews/MonthTabView.swift @@ -65,7 +65,7 @@ struct MonthTabView: View { VStack (spacing: 10) { ForEach(month.indices, id: \.self) { index in let week = month[index].week - WeekView(week) + WeekViewForMonth(week: week, vm: vm) } } .background { @@ -85,92 +85,29 @@ struct MonthTabView: View { } } - - @ViewBuilder - func WeekView(_ week: [Date.WeekDay]) -> some View { - HStack (spacing: 23) { - ForEach(week) { day in - VStack { - Text(day.date.format("dd")) - .font(.system(size: 15, weight: .bold)) - .foregroundStyle(isDateInCurrentMonth(day.date) ? isSameDate(day.date, vm.selectedDay) ? Color.white : Color.black: isSameDate(day.date, vm.selectedDay) ? Color.white : Color("greyForDaysInMonthTabView")) - } - .frame(width: 30, height: 30, alignment: .center) - .background( content: { - Group { - if isSameDate(day.date, vm.selectedDay) { - Color("blueColor") - } - else { - Color("background") - } - if isSameDate(day.date, vm.selectedDay) { - Color("blueColor") - } - } - } - ) - .overlay ( - Group { - if day.date.isToday && !isSameDate(day.date, vm.selectedDay) { - RoundedRectangle(cornerRadius: 100) - .stroke(Color("blueColor"), lineWidth: 2) - } - } - ) - .cornerRadius(15) - .onTapGesture { - 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.fetchWeekSchedule("", difBetweenWeeks) - } - vm.selectedDay = day.date - vm.updateSelectedDayIndex() - } - } - } - } - 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 { -// switch (vm.numOfGroup) { -// case "": -// vm.week -= 1 -// default: -// vm.fetchWeekSchedule("new week", -1) -// } 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.fetchWeekSchedule("", -5) + vm.week -= 5 + vm.fetchWeekSchedule("") } if let lastDate = monthSlider[currentMonthIndex].last?.week[6].date, currentMonthIndex == (monthSlider.count - 1) { -// switch (vm.numOfGroup) { -// case "": -// vm.week += 1 -// default: -// vm.fetchWeekSchedule("new week", 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.fetchWeekSchedule("", 5) + vm.week += 5 + vm.fetchWeekSchedule("") } } } diff --git a/Schedule ICTIS/Main/Views/TabViews/WeekTabView.swift b/Schedule ICTIS/Main/Views/TabViews/WeekTabView.swift index 7504705..978692d 100644 --- a/Schedule ICTIS/Main/Views/TabViews/WeekTabView.swift +++ b/Schedule ICTIS/Main/Views/TabViews/WeekTabView.swift @@ -17,7 +17,7 @@ struct WeekTabView: View { TabView(selection: $currentWeekIndex) { ForEach(weekSlider.indices, id: \.self) { index in let week = weekSlider[index] - WeekView(week) + WeekViewForWeek(weekSlider: $weekSlider, currentWeekIndex: $currentWeekIndex, createWeek: $createWeek, week: week, vm: vm) .padding(.horizontal, 15) .tag(index) } @@ -48,103 +48,6 @@ struct WeekTabView: View { } } } - - @ViewBuilder - func WeekView(_ week: [Date.WeekDay]) -> some View { - HStack (spacing: 10) { - ForEach(week) { day in - VStack (spacing: 1) { - Text(day.date.format("E")) - .font(.system(size: 15, weight: .semibold)) - .foregroundColor(day.date.format("E") == "Вс" ? Color(.red) : isSameDate(day.date, vm.selectedDay) ? Color("customGray1") : Color("customGray3")) - .padding(.top, 13) - .foregroundColor(.gray) - Text(day.date.format("dd")) - .font(.system(size: 15, weight: .bold)) - .foregroundStyle(isSameDate(day.date, vm.selectedDay) ? .white : .black) - .padding(.bottom, 13) - } - .frame(width: 43, height: 55, alignment: .center) - .background( content: { - Group { - if isSameDate(day.date, vm.selectedDay) { - Color("blueColor") - } - else { - Color(.white) - } - if isSameDate(day.date, vm.selectedDay) { - Color("blueColor") - } - } - } - ) - .overlay ( - Group { - if day.date.isToday && !isSameDate(day.date, vm.selectedDay) { - RoundedRectangle(cornerRadius: 15) - .stroke(Color("blueColor"), lineWidth: 2) - } - } - ) - .cornerRadius(15) - .onTapGesture { - vm.selectedDay = day.date - vm.updateSelectedDayIndex() - } - } - } - .background { - GeometryReader { - let minX = $0.frame(in: .global).minX - - Color.clear - .preference(key: OffsetKey.self, value: minX) - .onPreferenceChange(OffsetKey.self) { value in - if value.rounded() == 15 && createWeek { - paginateWeek() - - createWeek = false - } - } - } - } - } - - func paginateWeek() { - let calendar = Calendar.current - if weekSlider.indices.contains(currentWeekIndex) { - if let firstDate = weekSlider[currentWeekIndex].first?.date, - currentWeekIndex == 0 { - switch (vm.numOfGroup) { - case "": - vm.week -= 1 - default: - vm.fetchWeekSchedule("new week", -1) - } - 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) { - switch (vm.numOfGroup) { - case "": - vm.week += 1 - default: - vm.fetchWeekSchedule("new week", 1) - } - 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() - } - } - } } #Preview { diff --git a/Schedule ICTIS/Main/Views/TabViews/WeekViewForMonth.swift b/Schedule ICTIS/Main/Views/TabViews/WeekViewForMonth.swift new file mode 100644 index 0000000..49c6486 --- /dev/null +++ b/Schedule ICTIS/Main/Views/TabViews/WeekViewForMonth.swift @@ -0,0 +1,70 @@ +// +// WeekViewForMonth.swift +// Schedule ICTIS +// +// Created by G412 on 20.12.2024. +// + +import SwiftUI + +struct WeekViewForMonth: View { + let week: [Date.WeekDay] + @ObservedObject var vm: ScheduleViewModel + + var body: some View { + HStack(spacing: 23) { + ForEach(week) { day in + VStack { + Text(day.date.format("dd")) + .font(.system(size: 15, weight: .bold)) + .foregroundStyle(getForegroundColor(day: day)) + } + .frame(width: 30, height: 30, alignment: .center) + .background(getBackgroundColor(day: day)) + .overlay(overlay(day: day)) + .cornerRadius(15) + .onTapGesture { + handleTap(day: day) + } + } + } + } + + 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("") + } + vm.selectedDay = day.date + vm.updateSelectedDayIndex() + } +} diff --git a/Schedule ICTIS/Main/Views/TabViews/WeekViewForWeek.swift b/Schedule ICTIS/Main/Views/TabViews/WeekViewForWeek.swift new file mode 100644 index 0000000..7a75ab7 --- /dev/null +++ b/Schedule ICTIS/Main/Views/TabViews/WeekViewForWeek.swift @@ -0,0 +1,102 @@ +// +// WeekView.swift +// Schedule ICTIS +// +// Created by G412 on 20.12.2024. +// + +import SwiftUI + +struct WeekViewForWeek: View { + @Binding var weekSlider: [[Date.WeekDay]] + @Binding var currentWeekIndex: Int + @Binding var createWeek: Bool + let week: [Date.WeekDay] + @ObservedObject var vm: ScheduleViewModel + var body: some View { + HStack (spacing: 10) { + ForEach(week) { day in + VStack (spacing: 1) { + Text(day.date.format("E")) + .font(.system(size: 15, weight: .semibold)) + .foregroundColor(day.date.format("E") == "Вс" ? Color(.red) : isSameDate(day.date, vm.selectedDay) ? Color("customGray1") : Color("customGray3")) + .padding(.top, 13) + .foregroundColor(.gray) + Text(day.date.format("dd")) + .font(.system(size: 15, weight: .bold)) + .foregroundStyle(isSameDate(day.date, vm.selectedDay) ? .white : .black) + .padding(.bottom, 13) + } + .frame(width: 43, height: 55, alignment: .center) + .background( content: { + Group { + if isSameDate(day.date, vm.selectedDay) { + Color("blueColor") + } + else { + Color(.white) + } + if isSameDate(day.date, vm.selectedDay) { + Color("blueColor") + } + } + } + ) + .overlay ( + Group { + if day.date.isToday && !isSameDate(day.date, vm.selectedDay) { + RoundedRectangle(cornerRadius: 15) + .stroke(Color("blueColor"), lineWidth: 2) + } + } + ) + .cornerRadius(15) + .onTapGesture { + vm.selectedDay = day.date + vm.updateSelectedDayIndex() + } + } + } + .background { + GeometryReader { + let minX = $0.frame(in: .global).minX + + Color.clear + .preference(key: OffsetKey.self, value: minX) + .onPreferenceChange(OffsetKey.self) { value in + if value.rounded() == 15 && createWeek { + paginateWeek() + + createWeek = false + } + } + } + } + } + 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("") + 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("") + 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/Model/ClassModel.swift b/Schedule ICTIS/Model/ClassModel.swift index 649d7e5..87631cf 100644 --- a/Schedule ICTIS/Model/ClassModel.swift +++ b/Schedule ICTIS/Model/ClassModel.swift @@ -20,11 +20,16 @@ final class ClassModel: NSManagedObject, Identifiable { @NSManaged var important: Bool @NSManaged var online: String + static var dateNow: Date = .now + // Здесь мы выполняем дополнительную инициализацию, назначая значения по умолчанию override func awakeFromInsert() { super.awakeFromInsert() - let calendar = Calendar.current + let moscowTimeZone = TimeZone(identifier: "Europe/Moscow")! + var calendar = Calendar.current + calendar.timeZone = moscowTimeZone + let startTime = Date() let endTime = calendar.date(byAdding: .hour, value: 1, to: Date.init()) setPrimitiveValue("", forKey: "auditory") @@ -34,19 +39,20 @@ final class ClassModel: NSManagedObject, Identifiable { setPrimitiveValue("Нет", forKey: "notification") setPrimitiveValue(false, forKey: "important") setPrimitiveValue("Оффлайн", forKey: "online") - setPrimitiveValue(Date.init(), forKey: "day") - setPrimitiveValue(Date.init(), forKey: "starttime") + setPrimitiveValue(startTime, forKey: "day") + setPrimitiveValue(startTime, forKey: "starttime") setPrimitiveValue(endTime, forKey: "endtime") } } // Расширение для загрузки данных из памяти extension ClassModel { + // Получаем все данные из памяти private static var classesFetchRequest: NSFetchRequest { NSFetchRequest(entityName: "ClassModel") } - // Получаем все данные из памяти + // Получаем все данные и сортируем их по дню static func all() -> NSFetchRequest { let request: NSFetchRequest = classesFetchRequest request.sortDescriptors = [ @@ -55,3 +61,29 @@ extension ClassModel { return request } } + +extension ClassModel { + @discardableResult + static func makePreview(count: Int, in context: NSManagedObjectContext) -> [ClassModel] { + var classes = [ClassModel]() + for i in 0.. ClassModel { + return makePreview(count: 1, in: context)[0] + } + + static func empty(context: NSManagedObjectContext = ClassProvider.shared.viewContext) -> ClassModel { + return ClassModel(context: context) + } +} diff --git a/Schedule ICTIS/Provider/ClassProvider.swift b/Schedule ICTIS/Provider/ClassProvider.swift index c197b1f..f88ea6f 100644 --- a/Schedule ICTIS/Provider/ClassProvider.swift +++ b/Schedule ICTIS/Provider/ClassProvider.swift @@ -7,6 +7,7 @@ import Foundation import CoreData +import SwiftUI // Это класс служит посредником между View и моделью данных // Он позволяет открыть наш файл данных чтобы записывать и извлекать значения @@ -29,6 +30,9 @@ final class ClassProvider { private init() { // Открытие файла persistentContainer = NSPersistentContainer(name: "ClassDataModel") + if EnvironmentValues.isPreview { + persistentContainer.persistentStoreDescriptions.first?.url = .init(filePath: "/dev/null") + } // Выставляем флаг для автоматического сохранения изменений данных из Veiw в память persistentContainer.viewContext.automaticallyMergesChangesFromParent = true @@ -42,3 +46,9 @@ final class ClassProvider { } } + +extension EnvironmentValues { + static var isPreview: Bool { + return ProcessInfo.processInfo.environment["XCODE_RUNNING_FOR_PREVIEWS"] == "1" + } +} diff --git a/Schedule ICTIS/Utilities/Extensions/View+Extensions.swift b/Schedule ICTIS/Utilities/Extensions/View+Extensions.swift index bfe8449..60a3b1b 100644 --- a/Schedule ICTIS/Utilities/Extensions/View+Extensions.swift +++ b/Schedule ICTIS/Utilities/Extensions/View+Extensions.swift @@ -120,37 +120,6 @@ extension View { return formatter } - func checkStartTimeLessThenEndTime(_ startTime: Date, _ endTime: Date) -> Bool { - let calendar = Calendar.current - - let firstComponents = calendar.dateComponents([.hour, .minute], from: startTime) - let secondComponents = calendar.dateComponents([.hour, .minute], from: endTime) - - guard let startHours = firstComponents.hour, let startMinutes = firstComponents.minute else { - return false - } - guard let endHours = secondComponents.hour, let endMinutes = secondComponents.minute else { - return false - } - - print("\(startHours) - \(endHours)") - print("\(startMinutes) - \(endMinutes)") - if startHours > endHours { - return false - } - else if startHours == endHours { - if startMinutes < endMinutes { - return true - } - else { - return false - } - } - else { - return true - } - } - func checkUpFields(_ subject: String, _ auditory: String, _ professor: String, _ time1: Date, _ time3: Date) -> Bool { if (subject != "" || auditory != "" || professor != "") { return true diff --git a/Schedule ICTIS/ViewModel/ScheduleViewModel.swift b/Schedule ICTIS/ViewModel/ScheduleViewModel.swift index ee0d251..63fff54 100644 --- a/Schedule ICTIS/ViewModel/ScheduleViewModel.swift +++ b/Schedule ICTIS/ViewModel/ScheduleViewModel.swift @@ -30,14 +30,13 @@ final class ScheduleViewModel: ObservableObject { @Published var group: String = "" //MARK: Methods - func fetchWeekSchedule(_ group: String, _ num: Int = 0) { + func fetchWeekSchedule(_ group: String) { isLoading = true Task { do { var schedule: Schedule - if (num != 0) { - week += num - schedule = try await NetworkManager.shared.getScheduleForOtherWeek(week, numOfGroup) + if !self.numOfGroup.isEmpty { + schedule = try await NetworkManager.shared.getScheduleForOtherWeek(self.week, self.numOfGroup) } else { schedule = try await NetworkManager.shared.getSchedule(group)