From 0c35a1f10d444a987a1d11db7126460c84e0e5b0 Mon Sep 17 00:00:00 2001 From: nurazizah2471 <87691268+nurazizah2471@users.noreply.github.com> Date: Mon, 27 Nov 2023 18:08:17 +0700 Subject: [PATCH 1/3] feat: fixing indexPlayEpisode --- Moco/View/User/EpisodeView.swift | 2 +- Moco/View/User/StoryView.swift | 2 +- Moco/ViewModel/EpisodeViewModel.swift | 34 +++++++------ Moco/ViewModel/StoryViewViewModel.swift | 66 ++++++++++++------------- Moco/ViewModel/UserViewModel.swift | 28 ++++++----- 5 files changed, 69 insertions(+), 63 deletions(-) diff --git a/Moco/View/User/EpisodeView.swift b/Moco/View/User/EpisodeView.swift index 90d72a2..b98770d 100644 --- a/Moco/View/User/EpisodeView.swift +++ b/Moco/View/User/EpisodeView.swift @@ -74,7 +74,7 @@ struct EpisodeView: View { ) { if episode.isAvailable || index < userViewModel.userLogin!.availableEpisodeSum { Task { - episodeViewModel.setSelectedEpisode(episode) + episodeViewModel.setSelectedEpisode(episode, index) // open new story page storyViewModel.fetchStory(0, episodeViewModel.selectedEpisode!) diff --git a/Moco/View/User/StoryView.swift b/Moco/View/User/StoryView.swift index 5e3f671..63244ed 100644 --- a/Moco/View/User/StoryView.swift +++ b/Moco/View/User/StoryView.swift @@ -214,7 +214,7 @@ struct StoryView: View { } } .popUp(isActive: $svvm.isExitPopUpActive, title: "Yakin mau keluar?", cancelText: "Tidak", confirmText: "Ya") { - svvm.exit() + svvm.continueStory() } .popUp(isActive: $svvm.isEpisodeFinished, title: "Lanjutkan cerita?", cancelText: "Tidak", confirmText: "Lanjut") { svvm.continueStory() diff --git a/Moco/ViewModel/EpisodeViewModel.swift b/Moco/ViewModel/EpisodeViewModel.swift index 4647130..6d9f9fa 100644 --- a/Moco/ViewModel/EpisodeViewModel.swift +++ b/Moco/ViewModel/EpisodeViewModel.swift @@ -10,21 +10,23 @@ import SwiftData @Observable class EpisodeViewModel: BaseViewModel { static let shared = EpisodeViewModel() - + var selectedEpisode: EpisodeModel? + var indexEpisodePlay: Int? var episodes: [EpisodeModel]? - + init(modelContext: ModelContext? = nil) { super.init() if modelContext != nil { self.modelContext = modelContext } } - - func setSelectedEpisode(_ episode: EpisodeModel) { + + func setSelectedEpisode(_ episode: EpisodeModel, _ indexEpisode: Int) { selectedEpisode = episode + indexEpisodePlay = indexEpisode } - + func fetchEpisodes(storyThemeId: String) { let fetchDescriptor = FetchDescriptor( predicate: #Predicate { @@ -32,10 +34,10 @@ import SwiftData }, sortBy: [SortDescriptor(\.createdAt)] ) - + episodes = (try? modelContext?.fetch(fetchDescriptor) ?? []) ?? [] } - + func fetchAvailableEpisodes(storyThemeId: String) -> [EpisodeModel]? { let fetchDescriptor = FetchDescriptor( predicate: #Predicate { @@ -43,19 +45,21 @@ import SwiftData }, sortBy: [SortDescriptor(\.createdAt)] ) - + return (try? modelContext?.fetch(fetchDescriptor) ?? []) ?? [] } - + func setToAvailable(selectedStoryTheme: StoryThemeModel) { fetchEpisodes(storyThemeId: selectedStoryTheme.uid) - + if let availableEpisode = fetchAvailableEpisodes(storyThemeId: selectedStoryTheme.uid) { - episodes![availableEpisode.count].isAvailable = true - try? modelContext?.save() + if EpisodeViewModel.shared.indexEpisodePlay == availableEpisode.count - 1 { + episodes![availableEpisode.count].isAvailable = true + try? modelContext?.save() + } } } - + func getPromptByType(promptType: PromptType) -> [PromptModel] { let result = selectedEpisode?.stories? .sorted { @@ -66,10 +70,10 @@ import SwiftData .filter { $0.promptType == promptType } ?? [] - + return result } - + func getMazeProgress(promptId: String) -> (Double, Int, Int) { let mazePrompts = getPromptByType(promptType: .maze) guard mazePrompts.count > 0 else { return (0, 0, 0) } diff --git a/Moco/ViewModel/StoryViewViewModel.swift b/Moco/ViewModel/StoryViewViewModel.swift index 1c14bd1..1e4fe7d 100644 --- a/Moco/ViewModel/StoryViewViewModel.swift +++ b/Moco/ViewModel/StoryViewViewModel.swift @@ -9,7 +9,7 @@ import SwiftUI class StoryViewViewModel: ObservableObject { // MARK: - Environments stored property - + private(set) var userViewModel = UserViewModel.shared private(set) var storyThemeViewModel = StoryThemeViewModel.shared private(set) var storyViewModel = StoryViewModel.shared @@ -23,13 +23,13 @@ class StoryViewViewModel: ObservableObject { private(set) var settingsViewModel = SettingsViewModel.shared private(set) var navigate = RouteViewModel.shared private(set) var gameKitViewModel = GameKitViewModel.shared - + // MARK: - Static Variables - + private static let storyVolume: Float = 0.5 - + // MARK: - States - + @Published var scrollPosition: Int? = 0 @Published var isExitPopUpActive = false @Published var isEpisodeFinished = false @@ -46,15 +46,15 @@ class StoryViewViewModel: ObservableObject { @Published private var mazeQuestionIndex = 0 @Published var forceShowNext = false @Published var showPauseMenu = false - + // MARK: - Variables - + @Published var enableUI = true } extension StoryViewViewModel { // MARK: - Functions - + private func updateText() { guard storyContentViewModel.narratives!.indices.contains(narrativeIndex + 1) else { return } narrativeIndex += 1 @@ -63,18 +63,18 @@ extension StoryViewViewModel { self.updateText() } } - + func stop() { timerViewModel.stopTimer() audioViewModel.pauseAllSounds(.backsound) } - + private func startNarrative() { guard storyContentViewModel.narratives != nil else { return } narrativeIndex = -1 // updateText() } - + private func startPrompt() { if let storyPage = storyViewModel.storyPage, !storyPage.earlyPrompt { activePrompt = nil @@ -83,16 +83,16 @@ extension StoryViewViewModel { showPromptButton = false return } - + withAnimation(Animation.default.delay(promptViewModel.prompts![0].startTime)) { self.showPromptButton = true } } - + func onPageChange() { stop() setNewStoryPage(scrollPosition ?? -1) - + if let bgSound = storyContentViewModel.bgSound?.contentName { audioViewModel.playSound( soundFileName: bgSound, @@ -100,7 +100,7 @@ extension StoryViewViewModel { category: .backsound ) } - + startNarrative() if let storyPage = storyViewModel.storyPage { promptViewModel.fetchPrompts(storyPage) @@ -113,20 +113,20 @@ extension StoryViewViewModel { } } } - + func nextPage() { guard episodeViewModel.selectedEpisode!.stories!.count > - scrollPosition! + 1 + scrollPosition! + 1 else { isEpisodeFinished = true return } - + showPromptButton = false forceShowNext = false - + let nextPageBg = storyViewModel.getPageBackground(scrollPosition! + 1, episode: episodeViewModel.selectedEpisode!) - + peelBackground = AnyView(Image(nextPageBg ?? storyViewModel.storyPage!.background) .resizable() .scaledToFill() @@ -136,11 +136,11 @@ extension StoryViewViewModel { toBeExecutedByPeelEffect = { self.scrollPosition! += 1 self.peelEffectState = .stop - + self.onPageChange() } } - + func prevPage(_ targetScrollPosition: Int? = nil) { guard scrollPosition! > 0 else { return } if let targetScrollPositionParam = targetScrollPosition { @@ -155,7 +155,7 @@ extension StoryViewViewModel { scrollPosition! -= 1 } peelEffectState = .reverse - + peelBackground = AnyView(Image(storyViewModel.storyPage!.background) .resizable() .scaledToFill() @@ -165,26 +165,26 @@ extension StoryViewViewModel { self.peelEffectState = .stop self.isReversePeel = false } - + onPageChange() } - + private func setNewStoryPage(_ scrollPosition: Int) { if scrollPosition > -1 { storyViewModel.fetchStory(scrollPosition, episodeViewModel.selectedEpisode!) - + if let storyPage = storyViewModel.storyPage { storyContentViewModel.fetchStoryContents(storyPage) - + promptViewModel.fetchPrompts(storyPage) - + if let prompts = promptViewModel.prompts, prompts.first?.hints != nil { hintViewModel.fetchHints(prompts[0]) } } } } - + func onPressSoundButton() { if !isMuted { audioViewModel.mute() @@ -193,13 +193,13 @@ extension StoryViewViewModel { } isMuted.toggle() } - + func exit() { navigate.pop { self.stop() } } - + func continueStory() { episodeViewModel.setToAvailable(selectedStoryTheme: storyThemeViewModel.selectedStoryTheme!) userViewModel.addingAvailableEpisode() @@ -210,7 +210,7 @@ extension StoryViewViewModel { self.stop() } } - + func registerAchievement() { var achievementId = AchievementID.firstEpisode switch userViewModel.userLogin?.availableEpisodeSum { @@ -227,7 +227,7 @@ extension StoryViewViewModel { } gameKitViewModel.reportAchievement(achievementID: achievementId, percentComplete: 100) } - + func onAppear() { onPageChange() mazePromptViewModel.reset(true) diff --git a/Moco/ViewModel/UserViewModel.swift b/Moco/ViewModel/UserViewModel.swift index fb0b406..7eebae4 100644 --- a/Moco/ViewModel/UserViewModel.swift +++ b/Moco/ViewModel/UserViewModel.swift @@ -10,53 +10,55 @@ import SwiftData @Observable class UserViewModel: BaseViewModel { static var shared = UserViewModel() - + var users: [UserModel]? var userLogin: UserModel? - + init(modelContext: ModelContext? = nil) { super.init() if modelContext != nil { self.modelContext = modelContext } } - + func fetchUsers() { let fetchDescriptor = FetchDescriptor( sortBy: [SortDescriptor(\.createdAt)] ) - + users = (try? modelContext?.fetch(fetchDescriptor) ?? []) ?? [] } - + func addUser(userData: UserModel) { modelContext?.insert(userData) try? modelContext?.save() - + fetchUsers() } - + func setUserLogin(user: UserModel) { userLogin = user } - + func addingAvailableStoryTheme() { if let userLogin = userLogin { userLogin.availableStoryThemeSum += 1 try? modelContext?.save() } } - + func addingAvailableEpisode() { if let userLogin = userLogin { - userLogin.availableEpisodeSum += 1 - try? modelContext?.save() + if EpisodeViewModel.shared.indexEpisodePlay == userLogin.availableEpisodeSum - 1 { + userLogin.availableEpisodeSum += 1 + try? modelContext?.save() + } } } - + func deleteAllUsers() { fetchUsers() - + if let users = users { for user in users { modelContext?.delete(user) From b8a0a670b2de3a5f1fb346a1e48ce0d3fbb6e3fa Mon Sep 17 00:00:00 2001 From: nurazizah2471 <87691268+nurazizah2471@users.noreply.github.com> Date: Mon, 27 Nov 2023 18:10:00 +0700 Subject: [PATCH 2/3] feat: reset svvm --- Moco/View/User/StoryView.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Moco/View/User/StoryView.swift b/Moco/View/User/StoryView.swift index 63244ed..5e3f671 100644 --- a/Moco/View/User/StoryView.swift +++ b/Moco/View/User/StoryView.swift @@ -214,7 +214,7 @@ struct StoryView: View { } } .popUp(isActive: $svvm.isExitPopUpActive, title: "Yakin mau keluar?", cancelText: "Tidak", confirmText: "Ya") { - svvm.continueStory() + svvm.exit() } .popUp(isActive: $svvm.isEpisodeFinished, title: "Lanjutkan cerita?", cancelText: "Tidak", confirmText: "Lanjut") { svvm.continueStory() From 35ffff893671491c5c5d4cd86e062b70b27c2bf5 Mon Sep 17 00:00:00 2001 From: Aaron Christopher Tanhar Date: Tue, 28 Nov 2023 01:55:43 +0700 Subject: [PATCH 3/3] style: fix stylelint --- Moco/ViewModel/EpisodeViewModel.swift | 24 ++++----- Moco/ViewModel/StoryViewViewModel.swift | 66 ++++++++++++------------- Moco/ViewModel/UserViewModel.swift | 22 ++++----- 3 files changed, 56 insertions(+), 56 deletions(-) diff --git a/Moco/ViewModel/EpisodeViewModel.swift b/Moco/ViewModel/EpisodeViewModel.swift index 6d9f9fa..81683bd 100644 --- a/Moco/ViewModel/EpisodeViewModel.swift +++ b/Moco/ViewModel/EpisodeViewModel.swift @@ -10,23 +10,23 @@ import SwiftData @Observable class EpisodeViewModel: BaseViewModel { static let shared = EpisodeViewModel() - + var selectedEpisode: EpisodeModel? var indexEpisodePlay: Int? var episodes: [EpisodeModel]? - + init(modelContext: ModelContext? = nil) { super.init() if modelContext != nil { self.modelContext = modelContext } } - + func setSelectedEpisode(_ episode: EpisodeModel, _ indexEpisode: Int) { selectedEpisode = episode indexEpisodePlay = indexEpisode } - + func fetchEpisodes(storyThemeId: String) { let fetchDescriptor = FetchDescriptor( predicate: #Predicate { @@ -34,10 +34,10 @@ import SwiftData }, sortBy: [SortDescriptor(\.createdAt)] ) - + episodes = (try? modelContext?.fetch(fetchDescriptor) ?? []) ?? [] } - + func fetchAvailableEpisodes(storyThemeId: String) -> [EpisodeModel]? { let fetchDescriptor = FetchDescriptor( predicate: #Predicate { @@ -45,13 +45,13 @@ import SwiftData }, sortBy: [SortDescriptor(\.createdAt)] ) - + return (try? modelContext?.fetch(fetchDescriptor) ?? []) ?? [] } - + func setToAvailable(selectedStoryTheme: StoryThemeModel) { fetchEpisodes(storyThemeId: selectedStoryTheme.uid) - + if let availableEpisode = fetchAvailableEpisodes(storyThemeId: selectedStoryTheme.uid) { if EpisodeViewModel.shared.indexEpisodePlay == availableEpisode.count - 1 { episodes![availableEpisode.count].isAvailable = true @@ -59,7 +59,7 @@ import SwiftData } } } - + func getPromptByType(promptType: PromptType) -> [PromptModel] { let result = selectedEpisode?.stories? .sorted { @@ -70,10 +70,10 @@ import SwiftData .filter { $0.promptType == promptType } ?? [] - + return result } - + func getMazeProgress(promptId: String) -> (Double, Int, Int) { let mazePrompts = getPromptByType(promptType: .maze) guard mazePrompts.count > 0 else { return (0, 0, 0) } diff --git a/Moco/ViewModel/StoryViewViewModel.swift b/Moco/ViewModel/StoryViewViewModel.swift index 1e4fe7d..1c14bd1 100644 --- a/Moco/ViewModel/StoryViewViewModel.swift +++ b/Moco/ViewModel/StoryViewViewModel.swift @@ -9,7 +9,7 @@ import SwiftUI class StoryViewViewModel: ObservableObject { // MARK: - Environments stored property - + private(set) var userViewModel = UserViewModel.shared private(set) var storyThemeViewModel = StoryThemeViewModel.shared private(set) var storyViewModel = StoryViewModel.shared @@ -23,13 +23,13 @@ class StoryViewViewModel: ObservableObject { private(set) var settingsViewModel = SettingsViewModel.shared private(set) var navigate = RouteViewModel.shared private(set) var gameKitViewModel = GameKitViewModel.shared - + // MARK: - Static Variables - + private static let storyVolume: Float = 0.5 - + // MARK: - States - + @Published var scrollPosition: Int? = 0 @Published var isExitPopUpActive = false @Published var isEpisodeFinished = false @@ -46,15 +46,15 @@ class StoryViewViewModel: ObservableObject { @Published private var mazeQuestionIndex = 0 @Published var forceShowNext = false @Published var showPauseMenu = false - + // MARK: - Variables - + @Published var enableUI = true } extension StoryViewViewModel { // MARK: - Functions - + private func updateText() { guard storyContentViewModel.narratives!.indices.contains(narrativeIndex + 1) else { return } narrativeIndex += 1 @@ -63,18 +63,18 @@ extension StoryViewViewModel { self.updateText() } } - + func stop() { timerViewModel.stopTimer() audioViewModel.pauseAllSounds(.backsound) } - + private func startNarrative() { guard storyContentViewModel.narratives != nil else { return } narrativeIndex = -1 // updateText() } - + private func startPrompt() { if let storyPage = storyViewModel.storyPage, !storyPage.earlyPrompt { activePrompt = nil @@ -83,16 +83,16 @@ extension StoryViewViewModel { showPromptButton = false return } - + withAnimation(Animation.default.delay(promptViewModel.prompts![0].startTime)) { self.showPromptButton = true } } - + func onPageChange() { stop() setNewStoryPage(scrollPosition ?? -1) - + if let bgSound = storyContentViewModel.bgSound?.contentName { audioViewModel.playSound( soundFileName: bgSound, @@ -100,7 +100,7 @@ extension StoryViewViewModel { category: .backsound ) } - + startNarrative() if let storyPage = storyViewModel.storyPage { promptViewModel.fetchPrompts(storyPage) @@ -113,20 +113,20 @@ extension StoryViewViewModel { } } } - + func nextPage() { guard episodeViewModel.selectedEpisode!.stories!.count > - scrollPosition! + 1 + scrollPosition! + 1 else { isEpisodeFinished = true return } - + showPromptButton = false forceShowNext = false - + let nextPageBg = storyViewModel.getPageBackground(scrollPosition! + 1, episode: episodeViewModel.selectedEpisode!) - + peelBackground = AnyView(Image(nextPageBg ?? storyViewModel.storyPage!.background) .resizable() .scaledToFill() @@ -136,11 +136,11 @@ extension StoryViewViewModel { toBeExecutedByPeelEffect = { self.scrollPosition! += 1 self.peelEffectState = .stop - + self.onPageChange() } } - + func prevPage(_ targetScrollPosition: Int? = nil) { guard scrollPosition! > 0 else { return } if let targetScrollPositionParam = targetScrollPosition { @@ -155,7 +155,7 @@ extension StoryViewViewModel { scrollPosition! -= 1 } peelEffectState = .reverse - + peelBackground = AnyView(Image(storyViewModel.storyPage!.background) .resizable() .scaledToFill() @@ -165,26 +165,26 @@ extension StoryViewViewModel { self.peelEffectState = .stop self.isReversePeel = false } - + onPageChange() } - + private func setNewStoryPage(_ scrollPosition: Int) { if scrollPosition > -1 { storyViewModel.fetchStory(scrollPosition, episodeViewModel.selectedEpisode!) - + if let storyPage = storyViewModel.storyPage { storyContentViewModel.fetchStoryContents(storyPage) - + promptViewModel.fetchPrompts(storyPage) - + if let prompts = promptViewModel.prompts, prompts.first?.hints != nil { hintViewModel.fetchHints(prompts[0]) } } } } - + func onPressSoundButton() { if !isMuted { audioViewModel.mute() @@ -193,13 +193,13 @@ extension StoryViewViewModel { } isMuted.toggle() } - + func exit() { navigate.pop { self.stop() } } - + func continueStory() { episodeViewModel.setToAvailable(selectedStoryTheme: storyThemeViewModel.selectedStoryTheme!) userViewModel.addingAvailableEpisode() @@ -210,7 +210,7 @@ extension StoryViewViewModel { self.stop() } } - + func registerAchievement() { var achievementId = AchievementID.firstEpisode switch userViewModel.userLogin?.availableEpisodeSum { @@ -227,7 +227,7 @@ extension StoryViewViewModel { } gameKitViewModel.reportAchievement(achievementID: achievementId, percentComplete: 100) } - + func onAppear() { onPageChange() mazePromptViewModel.reset(true) diff --git a/Moco/ViewModel/UserViewModel.swift b/Moco/ViewModel/UserViewModel.swift index 7eebae4..00d0c17 100644 --- a/Moco/ViewModel/UserViewModel.swift +++ b/Moco/ViewModel/UserViewModel.swift @@ -10,43 +10,43 @@ import SwiftData @Observable class UserViewModel: BaseViewModel { static var shared = UserViewModel() - + var users: [UserModel]? var userLogin: UserModel? - + init(modelContext: ModelContext? = nil) { super.init() if modelContext != nil { self.modelContext = modelContext } } - + func fetchUsers() { let fetchDescriptor = FetchDescriptor( sortBy: [SortDescriptor(\.createdAt)] ) - + users = (try? modelContext?.fetch(fetchDescriptor) ?? []) ?? [] } - + func addUser(userData: UserModel) { modelContext?.insert(userData) try? modelContext?.save() - + fetchUsers() } - + func setUserLogin(user: UserModel) { userLogin = user } - + func addingAvailableStoryTheme() { if let userLogin = userLogin { userLogin.availableStoryThemeSum += 1 try? modelContext?.save() } } - + func addingAvailableEpisode() { if let userLogin = userLogin { if EpisodeViewModel.shared.indexEpisodePlay == userLogin.availableEpisodeSum - 1 { @@ -55,10 +55,10 @@ import SwiftData } } } - + func deleteAllUsers() { fetchUsers() - + if let users = users { for user in users { modelContext?.delete(user)