Skip to content

Commit d3c02c9

Browse files
authored
[Feature/#82] 순서 변경 및 길이 편집 로직 보완 및 UI연결 (#95)
* [FIX]: 유즈케이스에서 순서 변경이 되지 않던 버그 * [FEAT]: VideoPresentationModel을 비교할 수 있는 기능 추가 * [FEAT]: 공유 편집 화면에서 동영상의 순서를 변경하는 이벤트 정의 * [FEAT]: 공유 편집 화면 뷰컨트롤러에 순서 변경 기능 추가 * [FEAT]: 공유 편집 화면의 뷰모델이 뷰의 동영상 순서 변경 이벤트를 처리하는 기능 추가 * [FIX]: 구간 편집 저장 버튼을 눌러도 뷰모델에 반영되지 않던 버그 * [FIX]: 클래스인 URL을 비교하고 있어 비교되지 않던 버그 * [FEAT]: 셀 이동 시 부드러운 애니메이션 및 이동한 셀을 가운데 화면으로 포커싱하는 기능 추가 * [REFACTOR]: 불필요한 코드 제거 * [FIX]: 리스트의 인덱스를 기반으로 새 비디오 목록 생성 및 대입하도록 변경 * [REFACTOR]: 주석 제거
1 parent 00aff5c commit d3c02c9

File tree

6 files changed

+70
-34
lines changed

6 files changed

+70
-34
lines changed

Data/Data/Element/EditVideoElement.swift

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,12 @@ struct EditVideoElement: Codable, Hashable {
1818
let endTime: Double
1919

2020
func hash(into hasher: inout Hasher) {
21-
// hasher.combine(url.lastPathComponent)
2221
hasher.combine(name)
2322
}
2423

2524
static func == (lhs: EditVideoElement, rhs: EditVideoElement) -> Bool {
2625
return lhs.name == rhs.name
2726
}
28-
// lhs.url.lastPathComponent == rhs.url.lastPathComponent &&
2927
}
3028

3129
struct User: Codable, Hashable {

Domain/UseCase/VideoUseCase.swift

Lines changed: 21 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import Interfaces
1515
public final class VideoUseCase {
1616
private var cancellables: Set<AnyCancellable> = []
1717
private var sharedVideos: [SharedVideo] = []
18-
private var editingVideos = [String: Video]()
18+
private var editingVideos = [Video]()
1919
private let sharingVideoRepository: SharingVideoRepositoryInterface
2020
private let editVideoRepository: EditVideoRepositoryInterface
2121

@@ -61,7 +61,7 @@ extension VideoUseCase: EditVideoUseCaseInterface {
6161
public func fetchVideos() async -> [Video] {
6262
var videos = [Video]()
6363
let sortedVideos = sharedVideos
64-
.sorted { $0.localUrl.path < $1.localUrl.path }
64+
.sorted { $0.localUrl.lastPathComponent < $1.localUrl.lastPathComponent }
6565

6666
for (index, video) in sortedVideos.enumerated() {
6767
let duration = await duration(url: video.localUrl)
@@ -76,8 +76,8 @@ extension VideoUseCase: EditVideoUseCaseInterface {
7676
videos.append(video)
7777
}
7878

79-
videos.forEach { editingVideos[$0.url.path] = $0 }
8079
editVideoRepository.initializedVideo(videos)
80+
editingVideos = videos
8181
return videos
8282
}
8383

@@ -87,7 +87,7 @@ extension VideoUseCase: EditVideoUseCaseInterface {
8787
}
8888

8989
public func reArrangingVideo(url: URL, index: Int) {
90-
let videos = updatedVideos(url: url, index: index)
90+
let videos = updatedVideos(url: url, to: index)
9191
editVideoRepository.reArrangingVideo(videos)
9292
}
9393
}
@@ -107,12 +107,16 @@ private extension VideoUseCase {
107107
.store(in: &cancellables)
108108

109109
editVideoRepository.editedVideos
110-
.subscribe(editedVideos)
110+
.sink(with: self) { (owner, videos) in
111+
owner.editingVideos = videos
112+
owner.editedVideos.send(videos)
113+
}
111114
.store(in: &cancellables)
112115
}
113116

114117
func updatedVideo(url: URL, startTime: Double, endTime: Double) -> Video? {
115-
guard let video = editingVideos[url.path] else { return nil }
118+
guard let video = editingVideos.first(where: { $0.url.path == url.path })
119+
else { return nil }
116120

117121
let newVideo = Video(
118122
url: video.url,
@@ -125,36 +129,29 @@ private extension VideoUseCase {
125129
endTime: endTime
126130
)
127131

128-
editingVideos[url.path] = video
129-
130132
return newVideo
131133
}
132134

133-
func updatedVideos(url: URL, index: Int) -> [Video] {
134-
guard let video = editingVideos[url.path] else { return [] }
135-
var newVideos = [Video]()
136-
let beforeIndex = video.index
137-
let adder = beforeIndex < index ? -1 : 1
138-
139-
let lowerBound = min(beforeIndex, index)
140-
let upperBound = min(beforeIndex, index)
141-
142-
let videos = editingVideos.values
143-
.filter { $0.index >= lowerBound && $0.index < upperBound }
144-
.map { updatedVideo(video: $0, index: index + adder) }
135+
func updatedVideos(url: URL, to index: Int) -> [Video] {
136+
guard let oldIndex = editingVideos.firstIndex(where: { $0.url.lastPathComponent == url.lastPathComponent })
137+
else { return editingVideos }
145138

146-
newVideos.append(contentsOf: videos)
147-
newVideos.append(updatedVideo(video: video, index: index))
148-
newVideos.forEach { editingVideos[$0.url.path] = $0 }
139+
let video = editingVideos.remove(at: oldIndex)
140+
editingVideos.insert(video, at: index)
149141

142+
let listIndexOrderedVideo = editingVideos.enumerated().map { (index, video) in
143+
updatedVideo(video: video, index: index)
144+
}
145+
146+
editingVideos = listIndexOrderedVideo
150147
return newVideos
151148
}
152149

153150
func updatedVideo(video: Video, index: Int) -> Video {
154151
return Video(
155152
url: video.url,
156153
name: video.name,
157-
index: video.index,
154+
index: index,
158155
duration: video.duration,
159156
author: video.author,
160157
editor: video.editor,

Feature/Feature/PresentationModel/VideoPresentationModel.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,10 @@ struct VideoPresentationModel {
1616
let endTime: Double
1717
let frameImage: UIImageWrapper
1818
}
19+
20+
extension VideoPresentationModel: Equatable {
21+
static func == (lhs: VideoPresentationModel, rhs: VideoPresentationModel) -> Bool {
22+
if lhs.url == rhs.url { return true }
23+
return false
24+
}
25+
}

Feature/Feature/SharedVideoEditView/SharedVideoEditViewController.swift

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -453,14 +453,25 @@ extension SharedVideoEditViewController: UICollectionViewDropDelegate {
453453

454454
snapshot.deleteItems(draggedItems)
455455
let targetIndex = destinationIndexPath.item
456+
456457
let currentItems = snapshot.itemIdentifiers
457458
var updatedItems = currentItems
458459
updatedItems.insert(contentsOf: draggedItems, at: targetIndex)
459-
460-
applySnapShot(with: updatedItems)
461460

462461
coordinator.items.forEach { item in
463462
coordinator.drop(item.dragItem, toItemAt: destinationIndexPath)
464463
}
464+
465+
applySnapShot(with: updatedItems)
466+
467+
collectionView.scrollToItem(
468+
at: destinationIndexPath,
469+
at: .centeredHorizontally,
470+
animated: true
471+
)
472+
473+
guard let reorderItem = videoTimelineDataSource.itemIdentifier(for: destinationIndexPath) else { return }
474+
475+
input.send(.timelineCellOrderDidChanged(to: targetIndex, url: reorderItem.url))
465476
}
466477
}

Feature/Feature/SharedVideoEditView/ViewModel/SharedVideoEditViewInput.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,5 @@ enum SharedVideoEditViewInput {
1313
case sliderModelLowerValueDidChanged(value: Double)
1414
case sliderModelUpperValueDidChanged(value: Double)
1515
case sliderEditSaveButtonDidTapped
16+
case timelineCellOrderDidChanged(to: Int, url: URL)
1617
}

Feature/Feature/SharedVideoEditView/ViewModel/SharedVideoEditViewModel.swift

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,18 @@ extension SharedVideoEditViewModel {
4343
owner.updateTappedVideoPresentationModel(upperValue: value)
4444
case .sliderEditSaveButtonDidTapped:
4545
guard let currentTappedVideoPresentationModel = owner.tappedVideoPresentationModel else { return }
46-
46+
if let index = owner.videoPresentationModels.firstIndex(where: {
47+
$0 == currentTappedVideoPresentationModel
48+
}) {
49+
owner.videoPresentationModels[index] = currentTappedVideoPresentationModel
50+
}
4751
owner.usecase.trimmingVideo(
4852
url: currentTappedVideoPresentationModel.url,
4953
startTime: currentTappedVideoPresentationModel.startTime,
5054
endTime: currentTappedVideoPresentationModel.endTime
5155
)
56+
case .timelineCellOrderDidChanged(let to, let url):
57+
owner.videoOrderChanged(to: to, url: url)
5258
}
5359
}
5460
.store(in: &cancellables)
@@ -69,19 +75,24 @@ private extension SharedVideoEditViewModel {
6975
if let currentTappedVideoPresentationModel = owner.tappedVideoPresentationModel {
7076
guard
7177
let tappedVideo = videos.first(
72-
where: { $0.url == currentTappedVideoPresentationModel.url }),
78+
where: { $0.url.path == currentTappedVideoPresentationModel.url.path }),
7379
let model = await owner.makeVideoPresentationModel(video: tappedVideo)
7480
else { return }
7581
owner.setTappedVideoPresentationModel(model: model)
7682
}
77-
7883
// Timeline 순서 편집 처리
79-
let newTimelineItems = await videos.asyncCompactMap { video in
84+
let orderdVideos = videos.sorted { $0.index < $1.index }
85+
var timeLineItem: [VideoTimelineItem] = []
86+
for video in orderdVideos {
8087
let asset = AVAsset(url: video.url)
8188
owner.appendVideoPresentationModels(video: video)
82-
return await owner.makeVideoTimelineItem(with: video.url, asset: asset)
89+
async let item = owner.makeVideoTimelineItem(with: video.url, asset: asset)
90+
await timeLineItem.append(item)
8391
}
84-
owner.output.send(.timelineItemsDidChanged(items: newTimelineItems))
92+
// let newTimelineItems = await orderdVideos.asyncCompactMap { video in
93+
// return await
94+
// }
95+
owner.output.send(.timelineItemsDidChanged(items: timeLineItem))
8596
}
8697
}
8798
.store(in: &cancellables)
@@ -236,4 +247,15 @@ private extension SharedVideoEditViewModel {
236247
setTappedVideoPresentationModel(model: tappedModel)
237248
}
238249
}
250+
251+
func videoOrderChanged(
252+
to: Int,
253+
url: URL
254+
) {
255+
guard let index = videoPresentationModels.firstIndex(where: { $0.url == url })
256+
else { return }
257+
let video = videoPresentationModels.remove(at: index)
258+
videoPresentationModels.insert(video, at: to)
259+
usecase.reArrangingVideo(url: video.url, index: to)
260+
}
239261
}

0 commit comments

Comments
 (0)