Skip to content

Commit

Permalink
Implement favorite groups
Browse files Browse the repository at this point in the history
  • Loading branch information
asiliuk committed Aug 7, 2020
1 parent 580b09a commit 73bac3e
Show file tree
Hide file tree
Showing 7 changed files with 90 additions and 15 deletions.
51 changes: 46 additions & 5 deletions BsuirScheduleApp/AppState/AllGroupsScreen.swift
Expand Up @@ -10,14 +10,39 @@ import BsuirApi
import Combine
import Foundation

final class FavoritesContainer {
@Published private(set) var favorites: Set<Int> {
didSet {
storage.set(favorites.sorted(), forKey: key)
}
}

init(storage: UserDefaults) {
self.storage = storage
self.favorites = Set(storage.object(forKey: key) as? [Int] ?? [])
}

func toggleFavorite(id: Int) {
if favorites.contains(id) {
favorites.remove(id)
} else {
favorites.insert(id)
}
}

private let key = "favorite-group-ids"
private let storage: UserDefaults
}

final class AllGroupsScreen: ObservableObject {

@Published var searchQuery: String = ""
let groups: LoadableContent<[AllGroupsScreenGroupSection]>

let requestManager: RequestsManager
init(requestManager: RequestsManager) {
init(requestManager: RequestsManager, favorites: FavoritesContainer) {
self.requestManager = requestManager
self.favorites = favorites
self.groups = LoadableContent(
requestManager
.request(BsuirTargets.Groups())
Expand All @@ -26,22 +51,32 @@ final class AllGroupsScreen: ObservableObject {
guard !query.isEmpty else { return groups }
return groups.filter { $0.name.starts(with: query) }
}
.map { .init($0) }
.combineLatest(favorites.$favorites.setFailureType(to: RequestsManager.RequestError.self))
.map { .init(favorites: $1, groups: $0) }
.eraseToLoading()
)
}

func screen(for group: AllGroupsScreenGroup) -> ScheduleScreen {
.group(group.group, requestManager: requestManager)
.group(group.group, favorites: favorites, requestManager: requestManager)
}

private let favorites: FavoritesContainer
private var cancellables = Set<AnyCancellable>()
}

extension Array where Element == AllGroupsScreenGroupSection {
init(_ groups: [Group]) {
init(favorites: Set<Int>, groups: [Group]) {
let favoritesGroup = AllGroupsScreenGroupSection(
title: "⭐️ Избранные",
groups: groups
.filter { favorites.contains($0.id) }
.sorted { $0.name < $1.name }
.map(AllGroupsScreenGroup.init)
)

let groupedGroups = Dictionary(grouping: groups, by: { $0.name.prefix(3) })
self = groupedGroups
let rest = groupedGroups
.sorted(by: { $0.key < $1.key })
.map { title, groups in
AllGroupsScreenGroupSection(
Expand All @@ -51,6 +86,12 @@ extension Array where Element == AllGroupsScreenGroupSection {
.map(AllGroupsScreenGroup.init)
)
}

if favoritesGroup.groups.isEmpty {
self = rest
} else {
self = [favoritesGroup] + rest
}
}
}

Expand Down
8 changes: 5 additions & 3 deletions BsuirScheduleApp/AppState/AllLecturersScreen.swift
Expand Up @@ -26,8 +26,9 @@ final class AllLecturersScreen: ObservableObject {
@Published var searchQuery: String = ""
let lecturers: LoadableContent<[AllLecturersScreenLecturer]>

init(requestManager: RequestsManager) {
init(requestManager: RequestsManager, favorites: FavoritesContainer) {
self.requestManager = requestManager
self.favorites = favorites
self.lecturers = LoadableContent(
requestManager.request(BsuirTargets.Employees())
.map { $0.map(AllLecturersScreenLecturer.init) }
Expand All @@ -40,9 +41,10 @@ final class AllLecturersScreen: ObservableObject {
}

func screen(for lecturer: AllLecturersScreenLecturer) -> ScheduleScreen {
.lecturer(lecturer.employee, requestManager: requestManager)
.lecturer(lecturer.employee, favorites: favorites, requestManager: requestManager)
}


private let favorites: FavoritesContainer
private let requestManager: RequestsManager
}

Expand Down
5 changes: 3 additions & 2 deletions BsuirScheduleApp/AppState/AppState.swift
Expand Up @@ -26,6 +26,7 @@ final class AppState: ObservableObject {
let requestManager: RequestsManager
init(requestManager: RequestsManager) { self.requestManager = requestManager }

private(set) lazy var allGroups = AllGroupsScreen(requestManager: requestManager)
private(set) lazy var allLecturers = AllLecturersScreen(requestManager: requestManager)
private lazy var favorites = FavoritesContainer(storage: .standard)
private(set) lazy var allGroups = AllGroupsScreen(requestManager: requestManager, favorites: favorites)
private(set) lazy var allLecturers = AllLecturersScreen(requestManager: requestManager, favorites: favorites)
}
7 changes: 6 additions & 1 deletion BsuirScheduleApp/AppState/GroupScreen.swift
Expand Up @@ -11,9 +11,14 @@ import Foundation

extension ScheduleScreen {

static func group(_ group: Group, requestManager: RequestsManager) -> Self {
static func group(_ group: Group, favorites: FavoritesContainer, requestManager: RequestsManager) -> Self {
Self(
name: group.name,
isFavorite: favorites.$favorites
.map { $0.contains(group.id) }
.removeDuplicates()
.eraseToAnyPublisher(),
toggleFavorite: { favorites.toggleFavorite(id: group.id) },
request: requestManager
.request(BsuirTargets.Schedule(agent: .groupID(group.id)))
.map { ($0.schedules, $0.examSchedules) }
Expand Down
4 changes: 3 additions & 1 deletion BsuirScheduleApp/AppState/LecturerScreen.swift
Expand Up @@ -12,9 +12,11 @@ import Foundation

extension ScheduleScreen {

static func lecturer(_ employee: Employee, requestManager: RequestsManager) -> Self {
static func lecturer(_ employee: Employee, favorites: FavoritesContainer, requestManager: RequestsManager) -> Self {
Self(
name: employee.fio,
isFavorite: Just(false).eraseToAnyPublisher(),
toggleFavorite: {},
request: requestManager
.request(BsuirTargets.EmployeeSchedule(id: employee.id))
.map { ($0.schedules ?? [], $0.examSchedules ?? []) }
Expand Down
14 changes: 12 additions & 2 deletions BsuirScheduleApp/AppState/ScheduleScreen.swift
Expand Up @@ -7,14 +7,24 @@ final class ScheduleScreen: ObservableObject {

let name: String
let schedule: LoadableContent<Schedule>

init(name: String, request: AnyPublisher<(schedule: [DaySchedule], exams: [DaySchedule]), RequestsManager.RequestError>) {
@Published private(set) var isFavorite: Bool = false
let toggleFavorite: () -> Void

init(
name: String,
isFavorite: AnyPublisher<Bool, Never>,
toggleFavorite: @escaping () -> Void,
request: AnyPublisher<(schedule: [DaySchedule], exams: [DaySchedule]), RequestsManager.RequestError>
) {
self.name = name
self.schedule = LoadableContent(
request
.map(Schedule.init)
.eraseToLoading()
)

self.toggleFavorite = toggleFavorite
isFavorite.assign(to: &self.$isFavorite)
}
}

Expand Down
16 changes: 15 additions & 1 deletion BsuirScheduleApp/Views/Schedule/ScheduleView.swift
Expand Up @@ -23,7 +23,20 @@ struct ScheduleView: View {
schedule
.onAppear(perform: screen.schedule.load)
.navigationBarTitle(Text(screen.name), displayMode: .inline)
.navigationBarItems(trailing: picker)
.navigationBarItems(trailing: HStack { favorite; picker })
}

private var favorite: some View {
Button(action: screen.toggleFavorite) {
Image(systemName: screen.isFavorite ? "star.fill" : "star")
.accentColor(.yellow)
.padding(.horizontal, 4)
}
.accessibility(
label: screen.isFavorite
? Text("Добавить в избранное")
: Text("Убрать из избранного")
)
}

private var picker: some View {
Expand All @@ -35,6 +48,7 @@ struct ScheduleView: View {
}
} label: {
Image(systemName: "calendar")
.padding(.horizontal, 4)
}
.accessibility(label: Text("Тип расписания"))
}
Expand Down

0 comments on commit 73bac3e

Please sign in to comment.