From 3053bd6ad89bc17cf399b91a89c960ed4ff5b4fb Mon Sep 17 00:00:00 2001 From: theFestest Date: Sun, 18 Jun 2023 15:35:55 -0400 Subject: [PATCH] Introduce secondary review sort order by review subject. Use default of Unsorted to maintain existing sorting behavior. --- ios/ReviewSession.swift | 42 ++++++++++++++++++++++++++ ios/ReviewSettingsViewController.swift | 19 +++++++++++- ios/Settings.swift | 24 +++++++++++++++ 3 files changed, 84 insertions(+), 1 deletion(-) diff --git a/ios/ReviewSession.swift b/ios/ReviewSession.swift index 038be33b..d018c988 100644 --- a/ios/ReviewSession.swift +++ b/ios/ReviewSession.swift @@ -204,6 +204,46 @@ class ReviewSession { _ = services.localCachingClient?.updateStudyMaterial(activeStudyMaterials!) } + private func sortReviewType() { + // Settings.secondaryReviewOrder -> (radical, kanji, vocab) order ranks + var subjectOrder = [UInt: (Int, Int, Int)]() + // Instead of more complex logic, let's have structed data and few sorting cases + subjectOrder[SecondaryReviewOrder.unsorted.rawValue] = (0, 0, 0) // Default, no sort + subjectOrder[SecondaryReviewOrder.radicalKanjiVocabulary.rawValue] = (1, 2, 3) + subjectOrder[SecondaryReviewOrder.radicalVocabularyKanji.rawValue] = (1, 3, 2) + subjectOrder[SecondaryReviewOrder.kanjiRadicalVocabulary.rawValue] = (2, 1, 3) + subjectOrder[SecondaryReviewOrder.kanjiVocabularyRadical.rawValue] = (3, 1, 2) + subjectOrder[SecondaryReviewOrder.vocabularyRadicalKanji.rawValue] = (2, 3, 1) + subjectOrder[SecondaryReviewOrder.vocabularyKanjiRadical.rawValue] = (3, 2, 1) + + let (radicalRank, kanjiRank, vocabRank) = subjectOrder[Settings.secondaryReviewOrder.rawValue]! + + let subjectRank = [TKMSubject.TypeEnum.radical.rawValue: radicalRank, + TKMSubject.TypeEnum.kanji.rawValue: kanjiRank, + TKMSubject.TypeEnum.vocabulary.rawValue: vocabRank] + + switch Settings.secondaryReviewOrder { + case .radicalKanjiVocabulary: fallthrough + case .radicalVocabularyKanji: fallthrough + case .kanjiRadicalVocabulary: fallthrough + case .kanjiVocabularyRadical: fallthrough + case .vocabularyRadicalKanji: fallthrough + case .vocabularyKanjiRadical: + reviewQueue.sort { (a, b: ReviewItem) -> Bool in + if subjectRank[a.assignment.subjectType.rawValue]! < + subjectRank[b.assignment.subjectType.rawValue]! { return true } + if subjectRank[a.assignment.subjectType.rawValue]! > + subjectRank[b.assignment.subjectType.rawValue]! { return false } + return false + } + case .unsorted: + break + + @unknown default: + fatalError() + } + } + private func sortReviewQueue() { reviewQueue.shuffle() switch Settings.reviewOrder { @@ -269,6 +309,8 @@ class ReviewSession { @unknown default: fatalError() } + // Apply (secondary) review type sort, if applicable. + sortReviewType() } private func availableRatio(_ assignment: TKMAssignment) -> TimeInterval { diff --git a/ios/ReviewSettingsViewController.swift b/ios/ReviewSettingsViewController.swift index 696cb4fd..00665774 100644 --- a/ios/ReviewSettingsViewController.swift +++ b/ios/ReviewSettingsViewController.swift @@ -1,4 +1,4 @@ -// Copyright 2022 David Sansome +// Copyright 2023 David Sansome // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -45,6 +45,12 @@ class ReviewSettingsViewController: UITableViewController, TKMViewController { accessoryType: .disclosureIndicator, target: self, action: #selector(didTapReviewOrder(_:)))) + model.add(BasicModelItem(style: .value1, + title: "Subject Order", + subtitle: secondaryReviewOrderValueText, + accessoryType: .disclosureIndicator, + target: self, + action: #selector(didTapSecondaryReviewOrder(_:)))) model.add(SwitchModelItem(style: .subtitle, title: "Back-to-back", subtitle: "Group Meaning and Reading together", @@ -204,6 +210,10 @@ class ReviewSettingsViewController: UITableViewController, TKMViewController { Settings.reviewOrder.description } + private var secondaryReviewOrderValueText: String { + Settings.secondaryReviewOrder.description + } + private var taskOrderValueText: String { Settings.meaningFirst ? "Meaning first" : "Reading first" } @@ -313,6 +323,13 @@ class ReviewSettingsViewController: UITableViewController, TKMViewController { navigationController?.pushViewController(vc, animated: true) } + @objc private func didTapSecondaryReviewOrder(_: BasicModelItem) { + let vs = SettingChoiceListViewController(setting: Settings.$secondaryReviewOrder, + title: "Review Subject Order") + vs.addChoicesFromEnum() + navigationController?.pushViewController(vs, animated: true) + } + @objc private func didTapFonts(_: BasicModelItem) { performSegue(withIdentifier: "fonts", sender: self) } diff --git a/ios/Settings.swift b/ios/Settings.swift index 0ada8170..55a27f4f 100644 --- a/ios/Settings.swift +++ b/ios/Settings.swift @@ -41,6 +41,28 @@ typealias SettingEnum = RawRepresentable & Codable & CaseIterable & CustomString } } +@objc enum SecondaryReviewOrder: UInt, SettingEnum { + case unsorted = 1 + case radicalKanjiVocabulary = 2 // (rkv) + case radicalVocabularyKanji = 3 // (rvk) + case kanjiRadicalVocabulary = 4 // (krv) + case kanjiVocabularyRadical = 5 // (kvr) + case vocabularyRadicalKanji = 6 // (vrk) + case vocabularyKanjiRadical = 7 // (vkr) + + var description: String { + switch self { + case .unsorted: return "Unsorted" + case .radicalKanjiVocabulary: return "Radical, Kanji, Vocabulary" + case .radicalVocabularyKanji: return "Radical, Vocabulary, Kanji" + case .kanjiRadicalVocabulary: return "Kanji, Radical, Vocabulary" + case .kanjiVocabularyRadical: return "Kanji, Vocabulary, Radical" + case .vocabularyRadicalKanji: return "Vocabulary, Radical, Kanji" + case .vocabularyKanjiRadical: return "Vocabulary, Kanji, Radical" + } + } +} + @objc enum InterfaceStyle: UInt, SettingEnum { case system = 1 case light = 2 @@ -176,6 +198,8 @@ protocol SettingProtocol { @Setting(true, #keyPath(showStatsSection)) static var showStatsSection: Bool @EnumSetting(ReviewOrder.random, #keyPath(reviewOrder)) static var reviewOrder: ReviewOrder + @EnumSetting(SecondaryReviewOrder.unsorted, + #keyPath(secondaryReviewOrder)) static var secondaryReviewOrder: SecondaryReviewOrder @Setting(5, #keyPath(reviewBatchSize)) static var reviewBatchSize: Int @Setting(Int.max, #keyPath(apprenticeLessonsLimit)) static var apprenticeLessonsLimit: Int @Setting(false, #keyPath(groupMeaningReading)) static var groupMeaningReading: Bool