LotsOfChanges

This commit is contained in:
Vladimir Dubovik 2024-12-06 18:25:17 +03:00
parent 0f8dcea0a6
commit e7510aef68
10 changed files with 217 additions and 35 deletions

View File

@ -0,0 +1,38 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0xFF",
"green" : "0x7A",
"red" : "0x00"
}
},
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0xFF",
"green" : "0xFF",
"red" : "0xFF"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,38 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0x0A",
"green" : "0x97",
"red" : "0x00"
}
},
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0xFF",
"green" : "0xFF",
"red" : "0xFF"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -9,11 +9,12 @@ import SwiftUI
struct ContentView: View { struct ContentView: View {
@State private var selectedTab: TabBarModel = .schedule @State private var selectedTab: TabBarModel = .schedule
@StateObject var vm = ViewModel()
var body: some View { var body: some View {
ZStack { ZStack {
switch selectedTab { switch selectedTab {
case .schedule: case .schedule:
MainView() MainView(vm: vm)
case .tasks: case .tasks:
Text("Tasks") Text("Tasks")
case .settings: case .settings:

View File

@ -0,0 +1,28 @@
//
// FirstLaunchScheduleView.swift
// Schedule ICTIS
//
// Created by G412 on 06.12.2024.
//
import SwiftUI
struct FirstLaunchScheduleView: View {
var body: some View {
VStack (alignment: .center) {
Spacer()
HStack {
Image(systemName: "pencil")
.font(.title)
Text("Введите свою группу")
.font(.system(size: 20, weight: .bold, design: .default))
}
.foregroundColor(Color("blueColor"))
Spacer()
}
}
}
#Preview {
FirstLaunchScheduleView()
}

View File

@ -9,40 +9,47 @@ import SwiftUI
struct MainView: View { struct MainView: View {
@State private var searchText: String = "" @State private var searchText: String = ""
@State private var currentDate: Date = .init() @State private var currentDate: Date = Date()
@State private var weekSlider: [[Date.WeekDay]] = [] @State private var weekSlider: [[Date.WeekDay]] = []
@State private var currentWeekIndex: Int = 1 @State private var currentWeekIndex: Int = 1
@State private var createWeek: Bool = false @State private var createWeek: Bool = false
@State private var isShowingMonthSlider: Bool = false @State private var isShowingMonthSlider: Bool = false
@StateObject var vm = ViewModel() @State private var isFirstAppearence = true
@ObservedObject var vm: ViewModel
var body: some View { var body: some View {
VStack { VStack {
SearchBarView(text: $searchText, vm: vm) SearchBarView(text: $searchText, vm: vm)
HeaderView() CurrentDateView()
ScheduleView(vm: vm) if (vm.isFirstStartOffApp) {
FirstLaunchScheduleView()
}
else {
ScheduleView(vm: vm)
}
} }
.background(Color("background")) .background(Color("background"))
.onAppear(perform: { .onAppear(perform: {
currentDate = vm.selectedDay
vm.updateSelectedDayIndex(currentDate)
if weekSlider.isEmpty { if weekSlider.isEmpty {
let currentWeek = Date().fetchWeek() let currentWeek = Date().fetchWeek()
if let firstDate = currentWeek.first?.date { if let firstDate = currentWeek.first?.date {
weekSlider.append(firstDate.createPrevioustWeek()) weekSlider.append(firstDate.createPrevioustWeek())
} }
weekSlider.append(currentWeek) weekSlider.append(currentWeek)
if let lastDate = currentWeek.last?.date { if let lastDate = currentWeek.last?.date {
weekSlider.append(lastDate.createNextWeek()) weekSlider.append(lastDate.createNextWeek())
} }
} }
vm.updateSelectedDayIndex(currentDate)
}) })
} }
@ViewBuilder @ViewBuilder
func HeaderView() -> some View { func CurrentDateView() -> some View {
VStack (alignment: .leading, spacing: 6) { VStack (alignment: .leading, spacing: 6) {
HStack { HStack {
VStack (alignment: .leading, spacing: 0) { VStack (alignment: .leading, spacing: 0) {
@ -147,6 +154,7 @@ struct MainView: View {
.onPreferenceChange(OffsetKey.self) { value in .onPreferenceChange(OffsetKey.self) { value in
if value.rounded() == 15 && createWeek { if value.rounded() == 15 && createWeek {
paginateWeek() paginateWeek()
createWeek = false createWeek = false
} }
} }
@ -158,6 +166,7 @@ struct MainView: View {
if weekSlider.indices.contains(currentWeekIndex) { if weekSlider.indices.contains(currentWeekIndex) {
if let firstDate = weekSlider[currentWeekIndex].first?.date, if let firstDate = weekSlider[currentWeekIndex].first?.date,
currentWeekIndex == 0 { currentWeekIndex == 0 {
vm.fetchWeekSchedule("new week", -1)
weekSlider.insert(firstDate.createPrevioustWeek(), at: 0) weekSlider.insert(firstDate.createPrevioustWeek(), at: 0)
weekSlider.removeLast() weekSlider.removeLast()
currentWeekIndex = 1 currentWeekIndex = 1
@ -165,6 +174,7 @@ struct MainView: View {
if let lastDate = weekSlider[currentWeekIndex].last?.date, if let lastDate = weekSlider[currentWeekIndex].last?.date,
currentWeekIndex == (weekSlider.count - 1) { currentWeekIndex == (weekSlider.count - 1) {
vm.fetchWeekSchedule("new week", 1)
weekSlider.append(lastDate.createNextWeek()) weekSlider.append(lastDate.createNextWeek())
weekSlider.removeFirst() weekSlider.removeFirst()
currentWeekIndex = weekSlider.count - 2 currentWeekIndex = weekSlider.count - 2
@ -174,5 +184,5 @@ struct MainView: View {
} }
#Preview { #Preview {
MainView() ContentView()
} }

View File

@ -11,34 +11,48 @@ struct ScheduleView: View {
@ObservedObject var vm: ViewModel @ObservedObject var vm: ViewModel
var body: some View { var body: some View {
ScrollView(.vertical, showsIndicators: false) { ScrollView(.vertical, showsIndicators: false) {
VStack (spacing: 12) { VStack (spacing: 20) {
ForEach(vm.classes.indices, id: \.self) { index in ForEach(vm.classes.indices, id: \.self) { index in
if index != 0 && index != 1 && index == vm.selectedIndex { if index != 0 && index != 1 && index == vm.selectedIndex {
let daySchedule = vm.classes[index] // Это массив строк для дня let daySchedule = vm.classes[index] // Это массив строк для дня
ForEach(daySchedule.indices.dropFirst(), id: \.self) { lessonIndex in ForEach(daySchedule.indices.dropFirst(), id: \.self) { lessonIndex in
let lesson = daySchedule[lessonIndex] // Это строка с расписанием одной пары let lesson = daySchedule[lessonIndex] // Это строка с расписанием одной пары
if !lesson.isEmpty { if !lesson.isEmpty {
HStack(spacing: 6) { HStack(spacing: 10) {
VStack { VStack {
Text(convertTimeString(vm.classes[1][lessonIndex])[0]) Text(convertTimeString(vm.classes[1][lessonIndex])[0])
.font(.system(size: 15, weight: .light)) .font(.system(size: 15, weight: .regular))
Text(convertTimeString(vm.classes[1][lessonIndex])[1]) Text(convertTimeString(vm.classes[1][lessonIndex])[1])
.font(.system(size: 15, weight: .light)) .font(.system(size: 15, weight: .regular))
} }
.padding(.top, 7)
.padding(.bottom, 7)
.padding(.leading, 10)
Rectangle() Rectangle()
.frame(width: 2) .frame(width: 2)
.frame(maxHeight: 100) .frame(maxHeight: UIScreen.main.bounds.height - 18)
.padding(.top, 7)
.padding(.bottom, 7)
.foregroundColor(onlineOrOffline(lesson) ? Color("greenForOffline") : Color("blueForOnline"))
Text(lesson) Text(lesson)
.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) .background(Color.white)
.padding(.horizontal) .cornerRadius(20)
} }
} }
} }
} }
} }
.padding(.bottom, 100)
.padding(.top, 10)
} }
} }
//ктбо2-6
func convertTimeString(_ input: String) -> [String] { func convertTimeString(_ input: String) -> [String] {
let parts = input.split(separator: "-") let parts = input.split(separator: "-")
@ -48,8 +62,17 @@ struct ScheduleView: View {
return [] return []
} }
} }
func onlineOrOffline(_ str: String) -> Bool {
if (MockData.onlineClasses.contains(str)) {
return false
}
else {
return true
}
}
} }
#Preview { #Preview {
MainView() ContentView()
} }

View File

@ -27,6 +27,7 @@ struct SearchBarView: View {
.onSubmit { .onSubmit {
isEditing = false isEditing = false
if (!text.isEmpty) { if (!text.isEmpty) {
vm.isFirstStartOffApp = false
vm.fetchWeekSchedule(text) vm.fetchWeekSchedule(text)
} }
} }
@ -76,5 +77,5 @@ struct SearchBarView: View {
} }
#Preview { #Preview {
MainView() ContentView()
} }

View File

@ -0,0 +1,21 @@
//
// MockData.swift
// Schedule ICTIS
//
// Created by G412 on 06.12.2024.
//
import Foundation
struct MockData {
static let onlineClasses: [String] = [
"пр.Академический курс иностранного языка Янкаускас Е. С. LMS",
"пр.Академический курс иностранного языка Янкаускас Е. С. LMS-3",
"пр.Введение в инженерную деятельность 1 п/г Михайлова В. Д. LMS 2 п/г Романенко К. С. 3 п/г Козловский А. В. 4 п/г Компаниец В. С. 5 п/г Олейников К. А. 6 п/г Прудников В. А. 7 п/г Петров Д. А. 8 п/г Григорян К. С.",
"пр.Иностранный язык Иностранный язык LMS",
"лек.Операционные системы 1 п/г Шкурко А. Н. Г-309 АКТРУ 2 п/г Дроздов С. Н. Г-333 3 п/г Нужнов Е. В. Г-301 Operating systems(Операционные системы) 4 п/г Самойлов А. Н. LMS",
"пр.Введение в инженерную деятельность 1 п/г Плёнкин А. П. LMS-1 2 п/г Кучеров С. А. 3 п/г Шкурко А. Н. 4 п/г Механцев Б. Е.",
"лек.Операционные системы 1 п/г Шкурко А. Н. Г-309 АКТРУ 2 п/г Дроздов С. Н. Г-333 3 п/г Нужнов Е. В. Г-301 Operating systems(Операционные системы) 4 п/г Самойлов А. Н. LMS"
]
}

View File

@ -8,15 +8,12 @@
import Foundation import Foundation
final class NetworkManager { final class NetworkManager {
//"https://webictis.sfedu.ru/schedule-api/?group=51.html&week=15"
//MARK: Properties //MARK: Properties
static let shared = NetworkManager() static let shared = NetworkManager()
private let decoder = JSONDecoder() private let decoder = JSONDecoder()
private let urlForGroup = "https://webictis.sfedu.ru/schedule-api/?query=" private let urlForGroup = "https://webictis.sfedu.ru/schedule-api/?query="
private let urlForWeek = "https://webictis.sfedu.ru/schedule-api/?group=51.html&week=15" private let urlForWeek = "https://webictis.sfedu.ru/schedule-api/?group="
private var groupString: String = ""
private var numOfGroup: String = ""
private var numOfWeek: String = ""
//MARK: Initializer //MARK: Initializer
private init() { private init() {
@ -24,16 +21,33 @@ final class NetworkManager {
} }
//MARK: Methods //MARK: Methods
func makeURL(_ group: String) -> String { func makeUrlForGroup(_ group: String) -> String {
return urlForGroup + group return urlForGroup + group
} }
func makeUrlForWeek(_ numOfWeek: Int, _ htmlNameOfGroup: String) -> String {
return urlForWeek + htmlNameOfGroup + "&" + String(numOfWeek)
}
func getSchedule(_ group: String) async throws -> Schedule { func getSchedule(_ group: String) async throws -> Schedule {
let newUrlForGroup = makeURL(group) let newUrlForGroup = makeUrlForGroup(group)
guard let url = URL(string: newUrlForGroup) else {throw NetworkError.invalidUrl} guard let url = URL(string: newUrlForGroup) else {throw NetworkError.invalidUrl}
let (data, response) = try await URLSession.shared.data(from: url) let (data, response) = try await URLSession.shared.data(from: url)
guard let response = response as? HTTPURLResponse, response.statusCode == 200 else {throw NetworkError.invalidResponse} guard let response = response as? HTTPURLResponse, response.statusCode == 200 else {throw NetworkError.invalidResponse}
do {
return try decoder.decode(Schedule.self, from: data)
}
catch {
throw NetworkError.invalidData
}
}
func getScheduleForOtherWeek(_ numOfWeek: Int, _ htmlNameOfGroup: String) async throws -> Schedule {
let newUrlForWeek = makeUrlForWeek(numOfWeek, htmlNameOfGroup)
guard let url = URL(string: newUrlForWeek) else {throw NetworkError.invalidUrl}
let (data, response) = try await URLSession.shared.data(from: url)
guard let response = response as? HTTPURLResponse, response.statusCode == 200 else {throw NetworkError.invalidResponse}
do { do {
return try decoder.decode(Schedule.self, from: data) return try decoder.decode(Schedule.self, from: data)
} }

View File

@ -18,23 +18,30 @@ final class ViewModel: ObservableObject {
table: [[]], table: [[]],
link: "" link: ""
) )
@Published var selectedDay: Date = Date() @Published var selectedDay: Date = .init()
@Published var selectedIndex: Int = 1 @Published var selectedIndex: Int = 1
@Published var classes: [[String]] = [] @Published var classes: [[String]] = []
@Published var week: Int = 0
init() { @Published var numOfGroup: String = ""
@Published var isFirstStartOffApp = true
}
//MARK: Methods //MARK: Methods
func fetchWeekSchedule(_ group: String) { func fetchWeekSchedule(_ group: String = "new week", _ num: Int = 0) {
Task { Task {
do { do {
let schedule = try await NetworkManager.shared.getSchedule(group) let schedule: Schedule
if (group == "new week") {
schedule = try await NetworkManager.shared.getScheduleForOtherWeek(week + num, numOfGroup)
}
else{
schedule = try await NetworkManager.shared.getSchedule(group)
}
weekSchedule = schedule.table weekSchedule = schedule.table
week = weekSchedule.week
numOfGroup = weekSchedule.group
print(week)
print(numOfGroup)
classes = weekSchedule.table classes = weekSchedule.table
print(weekSchedule.week)
} }
catch { catch {
if let error = error as? NetworkError { if let error = error as? NetworkError {
@ -45,6 +52,7 @@ final class ViewModel: ObservableObject {
} }
func updateSelectedDayIndex(_ date: Date) { func updateSelectedDayIndex(_ date: Date) {
selectedDay = date
switch date.format("E") { switch date.format("E") {
case "Пн": case "Пн":
selectedIndex = 2 selectedIndex = 2