/// <summary> /// Background task work method. /// </summary> private void DoPrepareSvg(object sender, DoWorkEventArgs e) { // Lock to allow only one of these operations at a time. lock (_updateLock) { KanjiDao dao = new KanjiDao(); // Get the kanji strokes. KanjiStrokes strokes = dao.GetKanjiStrokes(_kanjiEntity.DbKanji.ID); if (strokes != null && strokes.FramesSvg.Length > 0) { // If the strokes was successfuly retrieved, we have to read the compressed SVG contained inside. SharpVectors.Renderers.Wpf.WpfDrawingSettings settings = new SharpVectors.Renderers.Wpf.WpfDrawingSettings(); using (FileSvgReader r = new FileSvgReader(settings)) { // Unzip the stream and remove instances of "px" that are problematic for SharpVectors. string svgString = StringCompressionHelper.Unzip(strokes.FramesSvg); svgString = svgString.Replace("px", string.Empty); StrokesCount = Regex.Matches(svgString, "<circle").Count; using (MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes(svgString))) { // Then read the stream to a DrawingGroup. // We are forced to do this operation on the UI thread because DrawingGroups must // be always manipulated by the same thread. DispatcherHelper.Invoke(() => { StrokesDrawingGroup = r.Read(stream); SetCurrentStroke(1); }); } } } } }
/// <summary> /// Background task work method. /// </summary> private void DoPrepareSvg(object sender, DoWorkEventArgs e) { // Lock to allow only one of these operations at a time. lock (_updateLock) { KanjiDao dao = new KanjiDao(); // Get the kanji strokes. KanjiStrokes strokes = dao.GetKanjiStrokes(_kanjiEntity.DbKanji.ID); if (strokes != null && strokes.FramesSvg.Length > 0) { // If the strokes was successfuly retrieved, we have to read the compressed SVG contained inside. string svgString = StringCompressionHelper.Unzip(strokes.FramesSvg); StrokesCount = Regex.Matches(svgString, "<circle").Count; DispatcherHelper.Invoke(() => { StrokesImage = new Avalonia.Svg.Skia.SvgImage { Source = new SvgSource { Picture = new SKSvg().FromSvg(svgString) } }; SetCurrentStroke(1); }); } } }
/// <summary> /// Before going to the next step, read all items! /// </summary> public override bool OnNextStep() { // Initialize fields _parent.NewEntries = new List <SrsEntry>(); StringBuilder log = new StringBuilder(); log.AppendLine(string.Format("Starting import with {0} line(s).", _parent.CsvLines.Count)); int i = 0; var vocabDao = new VocabDao(); var kanjiDao = new KanjiDao(); vocabDao.OpenMassTransaction(); // Browse CSV lines! foreach (List <string> row in _parent.CsvLines) { log.AppendFormat("l{0}: ", ++i); // Attempt to read the entry. SrsEntry entry = ReadEntry(row, vocabDao, kanjiDao, log); log.AppendLine(); // Add the entry to the parent's list if not null. if (entry != null) { _parent.NewEntries.Add(entry); } } vocabDao.CloseMassTransaction(); // All items have been added. // Apply the timing preferences for items that do not have a review date. _parent.ApplyTiming(); // Pray for the plural log.AppendLine(string.Format("Finished with {0} new entries.", _parent.NewEntries.Count)); // Set the import log. We're good. _parent.ImportLog = log.ToString(); return(true); }
/// <summary> /// Builds a ViewModel aimed at editing an existing SrsEntry, /// or adding a pre-composed SrsEntry. /// </summary> /// <param name="entity">Entity to edit.</param> public SrsEntryViewModel(SrsEntry entity) { // Initialize fields. _entry = new ExtendedSrsEntry(entity); _originalNextReviewDate = entity.NextAnswerDate; _originalLevelValue = entity.CurrentGrade; _associatedKanjiString = Entry.AssociatedKanji; _associatedVocabString = Entry.AssociatedVocab; _srsEntryDao = new SrsEntryDao(); _kanjiDao = new KanjiDao(); _vocabDao = new VocabDao(); if (IsNew) { Entry.Tags = Properties.Settings.Default.LastSrsTagsValue; } // Create the relay commands. SubmitCommand = new RelayCommand(OnSubmit); CancelCommand = new RelayCommand(OnCancel); SrsProgressResetCommand = new RelayCommand(OnSrsProgressReset); ApplyAssociatedKanjiCommand = new RelayCommand(OnApplyAssociatedKanji); ApplyAssociatedVocabCommand = new RelayCommand(OnApplyAssociatedVocab); ToggleSuspendCommand = new RelayCommand(OnToggleSuspend); DeleteCommand = new RelayCommand(OnDelete); ToggleDateEditCommand = new RelayCommand(OnToggleDateEdit); DateToNowCommand = new RelayCommand(OnDateToNow); DateToNeverCommand = new RelayCommand(OnDateToNever); // Get the associated kanji or vocab. GetAssociatedKanji(); GetAssociatedVocab(); // Initialize the VM. _isFirstSrsLevelSelect = true; SrsLevelPickerVm = new SrsLevelPickerViewModel(); SrsLevelPickerVm.SrsLevelSelected += OnSrsLevelSelected; SrsLevelPickerVm.Initialize(_entry.CurrentGrade); }
/// <summary> /// Reads an SRS item from a field row using the parameters of the view model. /// </summary> /// <param name="row">Row to read.</param> /// <param name="log">Log under the form of a stringbuilder to inform the user about how everything goes.</param> /// <returns>The SRS item read if successful. A null value otherwise.</returns> private SrsEntry ReadEntry(List <string> row, VocabDao vocabDao, KanjiDao kanjiDao, StringBuilder log) { try { SrsEntry entry = new SrsEntry(); string kanjiReading = row[_kanjiReadingColumn]; if (string.IsNullOrEmpty(kanjiReading)) { log.AppendFormat("Empty kanji reading. Skipping."); return(null); } // Figure out item type. CsvItemType itemType = ReadItemType(row); if (itemType == CsvItemType.Kanji || (itemType == CsvItemType.Unspecified && (_noTypeBehavior == CsvImportNoTypeBehavior.AllKanji || (_noTypeBehavior == CsvImportNoTypeBehavior.Auto && kanjiReading.Length == 1)))) { // Three solutions to set as kanji: // 1. Item is manually specified as kanji in source data. // 2. Item is not specified and no type behavior is set to AllKanji. // 3. Item is not specified and no type behavior is set to Auto and the length of kanjiReading is exactly 1. entry.AssociatedKanji = kanjiReading; log.AppendFormat("Kanji: \"{0}\". ", kanjiReading); itemType = CsvItemType.Kanji; } else { // All other cases will lead to vocab. entry.AssociatedVocab = kanjiReading; log.AppendFormat("Vocab: \"{0}\". ", kanjiReading); itemType = CsvItemType.Vocab; } string readings = ReadAcceptedReadings(row); long?sequenceNumber = ReadSequenceNumber(row); if (ReadingAutofill || MeaningAutofill) { switch (itemType) { case CsvItemType.Kanji: var kanji = kanjiDao.GetFirstMatchingKanji(kanjiReading); if (kanji == null) { log.Append("Can't find kanji in database. Skipping."); return(null); } entry.LoadFromKanji(kanji); break; case CsvItemType.Vocab: var vocabs = string.IsNullOrEmpty(readings) ? vocabDao.GetMatchingVocab(kanjiReading) : vocabDao.GetVocabByReadings(kanjiReading, readings); if (sequenceNumber.HasValue) { vocabs = vocabs.Where(v => v.Seq == sequenceNumber); } var vocab = vocabs.FirstOrDefault(); if (vocab == null) { log.Append("Can't find vocab in database. Skipping."); return(null); } entry.LoadFromVocab(vocab); entry.AssociatedVocab = kanjiReading; entry.Readings = default(string); break; } } // Find readings. if (!ReadingAutofill || !string.IsNullOrEmpty(readings)) { entry.Readings = readings; } if (itemType == CsvItemType.Kanji && string.IsNullOrEmpty(entry.Readings)) { log.Append("Empty readings. Skipping."); return(null); } // Find meanings. string meanings = ReadAcceptedMeanings(row); if (!MeaningAutofill || !string.IsNullOrEmpty(meanings)) { entry.Meanings = meanings; } if (string.IsNullOrEmpty(entry.Meanings)) { log.Append("Empty meanings. Skipping."); return(null); } // Find all optional info. entry.MeaningNote = ReadMeaningNotes(row); entry.ReadingNote = ReadReadingNotes(row); entry.Tags = ReadTags(row); entry.CurrentGrade = ReadStartLevel(row); entry.NextAnswerDate = ReadNextReviewDate(row); log.Append("OK."); return(entry); } catch (Exception ex) { log.AppendFormat("Unknown error: \"{0}\". Skipping.", ex.Message); } return(null); }
public KanjiBusiness() { _kanjiDao = new KanjiDao(); }
/// <summary> /// Applies the timing to the given entries. /// </summary> /// <param name="entries">Entries to reschedule.</param> public void ApplyTiming(List <SrsEntry> entries) { if (TimingMode == ImportTimingMode.Spread) { int i = 0; TimeSpan delay = TimeSpan.Zero; List <SrsEntry> pickList = new List <SrsEntry>(entries); HashSet <char> countedKanji = entries.Select(e => e.AssociatedKanji) .Where(k => !string.IsNullOrEmpty(k)) .Select(k => k[0]).ToHashSet(); HashSet <char> kanjiAdded = new HashSet <char>(); HashSet <char> kanjiJustAdded = new HashSet <char>(); List <SrsEntry> kanjiToAdd = new List <SrsEntry>(); List <SrsEntry> vocabToAdd = new List <SrsEntry>(); List <SrsEntry> vocabNext = new List <SrsEntry>(); KanjiDao kanjiDao = new KanjiDao(); while (pickList.Any() || kanjiToAdd.Any() || vocabToAdd.Any() || vocabNext.Any()) { SrsEntry next = null; if (kanjiToAdd.Any()) { next = kanjiToAdd[0]; kanjiToAdd.RemoveAt(0); } else if (vocabToAdd.Any()) { next = vocabToAdd[0]; vocabToAdd.RemoveAt(0); } else if (pickList.Any()) { // Pick an item and remove it. int nextIndex = SpreadMode == ImportSpreadTimingMode.ListOrder ? 0 : _random.Next(pickList.Count); next = pickList[nextIndex]; pickList.RemoveAt(nextIndex); if (KanjiOrdered) { if (!string.IsNullOrEmpty(next.AssociatedVocab)) { bool skip = false; foreach (var kanji in next.AssociatedVocab.Where(c => c > '\u4e00' && c < '\u9fff' && !kanjiAdded.Contains(c))) { if (!countedKanji.Contains(kanji)) { kanjiAdded.Add(kanji); } else { if (kanjiToAdd.All(k => k.AssociatedKanji[0] != kanji)) { int index = pickList.FindIndex(k => !string.IsNullOrEmpty(k.AssociatedKanji) && k.AssociatedKanji[0] == kanji); if (index >= 0) { kanjiToAdd.Add(pickList[index]); pickList.RemoveAt(index); } } skip = true; } } if (skip || next.AssociatedVocab.Any(c => c > '\u4e00' && c < '\u9fff' && kanjiJustAdded.Contains(c))) { vocabNext.Add(next); continue; } } } } if (next != null) { // add kanji to set if (!string.IsNullOrEmpty(next.AssociatedKanji)) { kanjiAdded.Add(next.AssociatedKanji[0]); kanjiJustAdded.Add(next.AssociatedKanji[0]); } // Apply spread next.NextAnswerDate = DateTime.Now + delay; } // Increment i and add a day to the delay if i reaches the spread value. if (++i >= SpreadAmountPerInterval || next == null) { i = 0; delay += TimeSpan.FromDays(SpreadInterval); if (KanjiOrdered) { kanjiJustAdded.Clear(); // add vocab to queue once all kanji have been added vocabToAdd.AddRange(vocabNext.Where(v => !v.AssociatedVocab.Any(c => c > '\u4e00' && c < '\u9fff' && !kanjiAdded.Contains(c)))); vocabNext.RemoveAll(v => !v.AssociatedVocab.Any(c => c > '\u4e00' && c < '\u9fff' && !kanjiAdded.Contains(c))); } } } } else if (TimingMode == ImportTimingMode.Immediate) { foreach (SrsEntry entry in entries) { entry.NextAnswerDate = DateTime.Now; } } else if (TimingMode == ImportTimingMode.Never) { foreach (SrsEntry entry in entries) { entry.NextAnswerDate = null; } } else if (TimingMode == ImportTimingMode.Fixed) { foreach (SrsEntry entry in entries) { entry.NextAnswerDate = FixedDate; } } else if (TimingMode == ImportTimingMode.UseSrsLevel) { foreach (SrsEntry entry in entries) { entry.NextAnswerDate = SrsLevelStore.Instance.GetNextReviewDate(entry.CurrentGrade); } } }
public FilteredKanjiIterator(KanjiFilter filter) : base(filter) { _kanjiDao = new KanjiDao(); }