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
|
import Foundation
|
||||||
|
|
||||||
// MARK: - Welcome
|
// MARK: - Welcome
|
||||||
struct Schedule: Codable {
|
struct Schedule: Decodable {
|
||||||
let table: Table
|
let table: Table
|
||||||
let weeks: [Int]
|
let weeks: [Int]
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Table
|
// MARK: - Table
|
||||||
struct Table: Codable {
|
struct Table: Decodable {
|
||||||
let type, name: String
|
let type, name: String
|
||||||
let week: Int
|
let week: Int
|
||||||
let group: String
|
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 currentDate: Date = .init()
|
||||||
@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
|
||||||
|
@StateObject var vm = ViewModel()
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack {
|
VStack {
|
||||||
SearchBarView(text: $searchText)
|
SearchBarView(text: $searchText)
|
||||||
HeaderView()
|
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()
|
Spacer()
|
||||||
}
|
}
|
||||||
.background(.secondary.opacity(0.1))
|
.background(.secondary.opacity(0.1))
|
||||||
@ -34,7 +47,6 @@ struct ScheduleView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ViewBuilder
|
@ViewBuilder
|
||||||
@ -45,7 +57,6 @@ struct ScheduleView: View {
|
|||||||
Text(currentDate.format("EEEE"))
|
Text(currentDate.format("EEEE"))
|
||||||
.font(.system(size: 40, weight: .semibold))
|
.font(.system(size: 40, weight: .semibold))
|
||||||
.foregroundStyle(.black)
|
.foregroundStyle(.black)
|
||||||
// .background(Color.green)
|
|
||||||
HStack (spacing: 5) {
|
HStack (spacing: 5) {
|
||||||
Text(currentDate.format("dd"))
|
Text(currentDate.format("dd"))
|
||||||
.font(.system(size: 20, weight: .bold))
|
.font(.system(size: 20, weight: .bold))
|
||||||
@ -54,11 +65,9 @@ struct ScheduleView: View {
|
|||||||
.font(.system(size: 20, weight: .bold))
|
.font(.system(size: 20, weight: .bold))
|
||||||
.foregroundStyle(Color("grayForDate"))
|
.foregroundStyle(Color("grayForDate"))
|
||||||
}
|
}
|
||||||
// .background(.red)
|
|
||||||
}
|
}
|
||||||
.padding(.top, 8)
|
.padding(.top, 8)
|
||||||
.padding(.leading, 20)
|
.padding(.leading, 20)
|
||||||
// .background(Color.brown)
|
|
||||||
Spacer()
|
Spacer()
|
||||||
}
|
}
|
||||||
.frame(maxWidth: .infinity)
|
.frame(maxWidth: .infinity)
|
||||||
@ -67,12 +76,20 @@ struct ScheduleView: View {
|
|||||||
ForEach(weekSlider.indices, id: \.self) { index in
|
ForEach(weekSlider.indices, id: \.self) { index in
|
||||||
let week = weekSlider[index]
|
let week = weekSlider[index]
|
||||||
WeekView(week)
|
WeekView(week)
|
||||||
|
.padding(.horizontal, 15)
|
||||||
.tag(index)
|
.tag(index)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.padding(.horizontal, -15)
|
||||||
.tabViewStyle(.page(indexDisplayMode: .never))
|
.tabViewStyle(.page(indexDisplayMode: .never))
|
||||||
.frame(height: 90)
|
.frame(height: 90)
|
||||||
}
|
}
|
||||||
|
.onChange(of: currentWeekIndex, initial: false) { oldValue, newValue in
|
||||||
|
if newValue == 0 || newValue == (weekSlider.count - 1) {
|
||||||
|
createWeek = true
|
||||||
|
}
|
||||||
|
vm.updateSelectedIndex(newValue)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ViewBuilder
|
@ViewBuilder
|
||||||
@ -116,9 +133,51 @@ struct ScheduleView: View {
|
|||||||
.cornerRadius(15)
|
.cornerRadius(15)
|
||||||
.onTapGesture {
|
.onTapGesture {
|
||||||
currentDate = day.date
|
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