q
This commit is contained in:
parent
3670a0b01f
commit
4fdec23e52
15
Schedule ICTIS/Helpers/OffsetKey.swift
Normal file
15
Schedule ICTIS/Helpers/OffsetKey.swift
Normal file
@ -0,0 +1,15 @@
|
||||
//
|
||||
// OffsetKey.swift
|
||||
// Schedule ICTIS
|
||||
//
|
||||
// Created by G412 on 18.11.2024.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct OffsetKey: PreferenceKey {
|
||||
static var defaultValue: CGFloat = 0
|
||||
static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
|
||||
value = nextValue()
|
||||
}
|
||||
}
|
@ -8,13 +8,13 @@
|
||||
import Foundation
|
||||
|
||||
// MARK: - Welcome
|
||||
struct Schedule: Codable {
|
||||
struct Schedule: Decodable {
|
||||
let table: Table
|
||||
let weeks: [Int]
|
||||
}
|
||||
|
||||
// MARK: - Table
|
||||
struct Table: Codable {
|
||||
struct Table: Decodable {
|
||||
let type, name: String
|
||||
let week: Int
|
||||
let group: String
|
14
Schedule ICTIS/Network/NetworkError.swift
Normal file
14
Schedule ICTIS/Network/NetworkError.swift
Normal file
@ -0,0 +1,14 @@
|
||||
//
|
||||
// NetworkError.swift
|
||||
// NewsApp
|
||||
//
|
||||
// Created by Mironov Egor on 18.11.2024.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
enum NetworkError: String, Error {
|
||||
case invalidUrl = "Invalid URL"
|
||||
case invalidResponse = "Invalid response form the server"
|
||||
case invalidData = "Data received from the server is invalid"
|
||||
}
|
35
Schedule ICTIS/Network/NetworkManager.swift
Normal file
35
Schedule ICTIS/Network/NetworkManager.swift
Normal file
@ -0,0 +1,35 @@
|
||||
//
|
||||
// NetworkManager.swift
|
||||
// NewsApp
|
||||
//
|
||||
// Created by Egor Mironov on 18.11.2024.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
final class NetworkManager {
|
||||
|
||||
//MARK: Properties
|
||||
static let shared = NetworkManager()
|
||||
private let decoder = JSONDecoder()
|
||||
private let urlString = "https://webictis.sfedu.ru/schedule-api/?query=%D0%BA%D1%82%D0%B1%D0%BE2-6"
|
||||
|
||||
//MARK: Initializer
|
||||
private init() {
|
||||
decoder.dateDecodingStrategy = .iso8601
|
||||
}
|
||||
|
||||
//MARK: Methods
|
||||
func getSchedule() async throws -> Schedule {
|
||||
guard let url = URL(string: urlString) 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 {
|
||||
return try decoder.decode(Schedule.self, from: data)
|
||||
}
|
||||
catch {
|
||||
throw NetworkError.invalidData
|
||||
}
|
||||
}
|
||||
}
|
@ -12,10 +12,23 @@ struct ScheduleView: View {
|
||||
@State private var currentDate: Date = .init()
|
||||
@State private var weekSlider: [[Date.WeekDay]] = []
|
||||
@State private var currentWeekIndex: Int = 1
|
||||
@State private var createWeek: Bool = false
|
||||
@StateObject var vm = ViewModel()
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
SearchBarView(text: $searchText)
|
||||
HeaderView()
|
||||
ScrollView(.vertical) {
|
||||
VStack {
|
||||
ForEach(vm.weekSchedule, id: \.week) { day in
|
||||
HStack {
|
||||
Text(convertTimeString(day.table[1][1])[0])
|
||||
Text(convertTimeString(day.table[1][1])[9])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Spacer()
|
||||
}
|
||||
.background(.secondary.opacity(0.1))
|
||||
@ -34,7 +47,6 @@ struct ScheduleView: View {
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
@ -45,7 +57,6 @@ struct ScheduleView: View {
|
||||
Text(currentDate.format("EEEE"))
|
||||
.font(.system(size: 40, weight: .semibold))
|
||||
.foregroundStyle(.black)
|
||||
// .background(Color.green)
|
||||
HStack (spacing: 5) {
|
||||
Text(currentDate.format("dd"))
|
||||
.font(.system(size: 20, weight: .bold))
|
||||
@ -54,11 +65,9 @@ struct ScheduleView: View {
|
||||
.font(.system(size: 20, weight: .bold))
|
||||
.foregroundStyle(Color("grayForDate"))
|
||||
}
|
||||
// .background(.red)
|
||||
}
|
||||
.padding(.top, 8)
|
||||
.padding(.leading, 20)
|
||||
// .background(Color.brown)
|
||||
Spacer()
|
||||
}
|
||||
.frame(maxWidth: .infinity)
|
||||
@ -67,12 +76,20 @@ struct ScheduleView: View {
|
||||
ForEach(weekSlider.indices, id: \.self) { index in
|
||||
let week = weekSlider[index]
|
||||
WeekView(week)
|
||||
.padding(.horizontal, 15)
|
||||
.tag(index)
|
||||
}
|
||||
}
|
||||
.padding(.horizontal, -15)
|
||||
.tabViewStyle(.page(indexDisplayMode: .never))
|
||||
.frame(height: 90)
|
||||
}
|
||||
.onChange(of: currentWeekIndex, initial: false) { oldValue, newValue in
|
||||
if newValue == 0 || newValue == (weekSlider.count - 1) {
|
||||
createWeek = true
|
||||
}
|
||||
vm.updateSelectedIndex(newValue)
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
@ -116,9 +133,51 @@ struct ScheduleView: View {
|
||||
.cornerRadius(15)
|
||||
.onTapGesture {
|
||||
currentDate = day.date
|
||||
vm.updateSelectedDayIndex(currentDate)
|
||||
}
|
||||
}
|
||||
}
|
||||
.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() {
|
||||
if weekSlider.indices.contains(currentWeekIndex) {
|
||||
if let firstDate = weekSlider[currentWeekIndex].first?.date,
|
||||
currentWeekIndex == 0 {
|
||||
weekSlider.insert(firstDate.createPrevioustWeek(), at: 0)
|
||||
weekSlider.removeLast()
|
||||
currentWeekIndex = 1
|
||||
}
|
||||
|
||||
if let lastDate = weekSlider[currentWeekIndex].last?.date,
|
||||
currentWeekIndex == (weekSlider.count - 1) {
|
||||
weekSlider.append(lastDate.createNextWeek())
|
||||
weekSlider.removeFirst()
|
||||
currentWeekIndex = weekSlider.count - 2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func convertTimeString(_ input: String) -> [String] {
|
||||
let parts = input.split(separator: "-")
|
||||
if let firstPart = parts.first, let lastPart = parts.last {
|
||||
return [String(firstPart), String(lastPart)]
|
||||
} else {
|
||||
return []
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
60
Schedule ICTIS/ViewModel/ViewModel.swift
Normal file
60
Schedule ICTIS/ViewModel/ViewModel.swift
Normal file
@ -0,0 +1,60 @@
|
||||
//
|
||||
// ViewModel.swift
|
||||
// NewsApp
|
||||
//
|
||||
// Created by Mironov Egor on 18.11.2024.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
@MainActor
|
||||
final class ViewModel: ObservableObject {
|
||||
//MARK: Properties
|
||||
@Published var weekSchedule: [Table] = []
|
||||
@Published var selectedDay: Date = Date()
|
||||
@Published var selectedIndex: Int = 0
|
||||
|
||||
init() {
|
||||
fetchWeekSchedule()
|
||||
}
|
||||
|
||||
//MARK: Methods
|
||||
func fetchWeekSchedule(){
|
||||
Task {
|
||||
do {
|
||||
let schedule = try await NetworkManager.shared.getSchedule()
|
||||
weekSchedule = [schedule.table]
|
||||
}
|
||||
catch {
|
||||
if let error = error as? NetworkError {
|
||||
print(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func updateSelectedDayIndex(_ date: Date) {
|
||||
switch date.format("E") {
|
||||
case "Пн":
|
||||
selectedIndex = 1
|
||||
case "Вт":
|
||||
selectedIndex = 2
|
||||
case "Ср":
|
||||
selectedIndex = 3
|
||||
case "Чт":
|
||||
selectedIndex = 4
|
||||
case "Пт":
|
||||
selectedIndex = 5
|
||||
case "Сб":
|
||||
selectedIndex = 6
|
||||
default:
|
||||
selectedIndex = 7
|
||||
}
|
||||
print(selectedIndex)
|
||||
}
|
||||
|
||||
func updateSelectedIndex(_ index: Int) {
|
||||
selectedIndex = index
|
||||
print(selectedIndex)
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user