Skip to content

Commit

Permalink
chore: merge swift6 branch
Browse files Browse the repository at this point in the history
  • Loading branch information
forgotvas committed Dec 2, 2024
1 parent 20a9b62 commit 4f384cf
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 20 deletions.
8 changes: 6 additions & 2 deletions Core/Core/Data/Model/Data_Media.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@ import Foundation
public extension DataLayer {

// MARK: - CourseMedia
struct CourseMedia: Decodable, Sendable {
struct CourseMedia: Decodable, Sendable, Equatable {
public static func == (lhs: DataLayer.CourseMedia, rhs: DataLayer.CourseMedia) -> Bool {
lhs.image == rhs.image
}

public let image: DataLayer.Image

public init(image: DataLayer.Image) {
Expand Down Expand Up @@ -61,7 +65,7 @@ public extension DataLayer {

public extension DataLayer {
// MARK: - Image
struct Image: Codable, Sendable {
struct Image: Codable, Sendable, Equatable {
public let raw: String
public let small: String
public let large: String
Expand Down
16 changes: 12 additions & 4 deletions Core/Core/Domain/Model/CourseBlockModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,11 @@ public struct CourseProgress: Sendable {
}
}

public struct CourseChapter: Identifiable, Sendable {
public struct CourseChapter: Identifiable, Sendable, Equatable {
public static func == (lhs: CourseChapter, rhs: CourseChapter) -> Bool {
lhs.id == rhs.id &&
lhs.blockId == rhs.blockId
}

public let blockId: String
public let id: String
Expand All @@ -114,7 +118,11 @@ public struct CourseChapter: Identifiable, Sendable {
}
}

public struct CourseSequential: Identifiable, Sendable {
public struct CourseSequential: Identifiable, Sendable, Equatable {
public static func == (lhs: CourseSequential, rhs: CourseSequential) -> Bool {
lhs.id == rhs.id &&
lhs.blockId == rhs.blockId
}

public let blockId: String
public let id: String
Expand Down Expand Up @@ -154,7 +162,7 @@ public struct CourseSequential: Identifiable, Sendable {
}
}

public struct CourseVertical: Identifiable, Hashable, Sendable {
public struct CourseVertical: Identifiable, Hashable, Sendable, Equatable {
public func hash(into hasher: inout Hasher) {
hasher.combine(id)
}
Expand Down Expand Up @@ -215,7 +223,7 @@ public struct SequentialProgress: Sendable {
}
}

public struct CourseBlock: Hashable, Identifiable, Sendable {
public struct CourseBlock: Hashable, Identifiable, Sendable, Equatable {
public static func == (lhs: CourseBlock, rhs: CourseBlock) -> Bool {
lhs.id == rhs.id &&
lhs.blockId == rhs.blockId &&
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -668,6 +668,45 @@ public final class CourseContainerViewModel: BaseCourseViewModel {
)
}

@MainActor
func collectBlocks(
chapter: CourseChapter,
blockId: String,
state: DownloadViewState,
videoOnly: Bool = false
) async -> [CourseBlock] {
let sequentials = chapter.childs.filter { $0.id == blockId }
guard !sequentials.isEmpty else { return [] }

let blocks = sequentials.flatMap { $0.childs.flatMap { $0.childs } }
.filter { $0.isDownloadable && (!videoOnly || $0.type == .video) }

if state == .available, isShowedAllowLargeDownloadAlert(blocks: blocks) {
return []
}

guard let sequential = chapter.childs.first(where: { $0.id == blockId }) else {
return []
}

if state == .available {
analytics.bulkDownloadVideosSubsection(
courseID: courseStructure?.id ?? "",
sectionID: chapter.id,
subSectionID: sequential.id,
videos: blocks.count
)
} else if state == .finished {
analytics.bulkDeleteVideosSubsection(
courseID: courseStructure?.id ?? "",
subSectionID: sequential.id,
videos: blocks.count
)
}

return blocks
}

@MainActor
func isShowedAllowLargeDownloadAlert(blocks: [CourseBlock]) -> Bool {
waitingDownloads = nil
Expand Down
79 changes: 65 additions & 14 deletions Course/Course/Presentation/Subviews/CustomDisclosureGroup.swift
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ struct CustomDisclosureGroup: View {
let state = downloadAllButtonState(for: chapter, videoOnly: isVideo) {
Button(
action: {
downloadAllSubsections(in: chapter, state: state)
downloadAllSubsections(in: chapter, state: state)
}, label: {
switch state {
case .available:
Expand Down Expand Up @@ -84,7 +84,7 @@ struct CustomDisclosureGroup: View {
viewModel.router.showGatedContentError(url: courseVertical.webUrl)
return
}

viewModel.trackSequentialClicked(sequential)
if viewModel.config.uiComponents.courseDropDownNavigationEnabled {
viewModel.router.showCourseUnit(
Expand Down Expand Up @@ -142,9 +142,9 @@ struct CustomDisclosureGroup: View {
\(numPointsPossible)
"""
)
.font(Theme.Fonts.bodySmall)
.multilineTextAlignment(.leading)
.lineLimit(2)
.font(Theme.Fonts.bodySmall)
.multilineTextAlignment(.leading)
.lineLimit(2)
}
}
.foregroundColor(Theme.Colors.textPrimary)
Expand All @@ -162,7 +162,7 @@ struct CustomDisclosureGroup: View {
}
}
}

}
}
.padding(.horizontal, 16)
Expand Down Expand Up @@ -212,11 +212,11 @@ struct CustomDisclosureGroup: View {
for sequential in chapter.childs {
if videoOnly {
let isDownloadable = sequential.childs.flatMap {
$0.childs.filter({ $0.type == .video })
$0.childs.filter { $0.type == .video }
}.contains(where: { $0.isDownloadable })
guard isDownloadable else { return false }
guard isDownloadable else { continue }
}
if viewModel.sequentialsDownloadState[sequential.id] != nil {
if sequentialDownloadState(sequential, videoOnly: videoOnly) != nil {
return true
}
}
Expand All @@ -225,17 +225,39 @@ struct CustomDisclosureGroup: View {

private func downloadAllSubsections(in chapter: CourseChapter, state: DownloadViewState) {
Task {
await viewModel.onDownloadViewTap(chapter: chapter, state: state)
var allBlocks: [CourseBlock] = []
var sequentialsToDownload: [CourseSequential] = []
for sequential in chapter.childs {
let blocks = await viewModel.collectBlocks(
chapter: chapter,
blockId: sequential.id,
state: state,
videoOnly: isVideo
)
if !blocks.isEmpty {
allBlocks.append(contentsOf: blocks)
sequentialsToDownload.append(sequential)
}
}
await viewModel.download(
state: state,
blocks: allBlocks,
sequentials: sequentialsToDownload
)
}
}

private func downloadAllButtonState(for chapter: CourseChapter, videoOnly: Bool) -> DownloadViewState? {
if canDownloadAllSections(in: chapter, videoOnly: videoOnly) {
let downloads = chapter.childs.filter({ viewModel.sequentialsDownloadState[$0.id] != nil })

if downloads.contains(where: { viewModel.sequentialsDownloadState[$0.id] == .downloading }) {
var downloads: [DownloadViewState] = []
for sequential in chapter.childs {
if let state = sequentialDownloadState(sequential, videoOnly: videoOnly) {
downloads.append(state)
}
}
if downloads.contains(.downloading) {
return .downloading
} else if downloads.allSatisfy({ viewModel.sequentialsDownloadState[$0.id] == .finished }) {
} else if downloads.allSatisfy({ $0 == .finished }) {
return .finished
} else {
return .available
Expand All @@ -244,6 +266,35 @@ struct CustomDisclosureGroup: View {
return nil
}

private func sequentialDownloadState(_ sequential: CourseSequential, videoOnly: Bool) -> DownloadViewState? {
let blocks: [CourseBlock]
if videoOnly {
blocks = sequential.childs.flatMap { $0.childs }.filter { $0.isDownloadable && $0.type == .video }
} else {
blocks = sequential.childs.flatMap { $0.childs }.filter { $0.isDownloadable }
}
guard !blocks.isEmpty else { return nil }
var blockStates: [DownloadViewState] = []
for block in blocks {
if let task = viewModel.courseDownloadTasks.first(where: { $0.blockId == block.id }) {
switch task.state {
case .waiting, .inProgress:
blockStates.append(.downloading)
case .finished:
blockStates.append(.finished)
}
} else {
blockStates.append(.available)
}
}
if blockStates.contains(.downloading) {
return .downloading
} else if blockStates.allSatisfy({ $0 == .finished }) {
return .finished
} else {
return .available
}
}
}

#if DEBUG
Expand Down

0 comments on commit 4f384cf

Please sign in to comment.