Skip to content

Commit

Permalink
Merge pull request #205 from m-edlund/feature/FrequencyField
Browse files Browse the repository at this point in the history
feat: frequency field
  • Loading branch information
arianneorpilla authored May 14, 2023
2 parents 8c99c1e + b1f3756 commit 61a243e
Show file tree
Hide file tree
Showing 5 changed files with 130 additions and 1 deletion.
1 change: 1 addition & 0 deletions yuuna/lib/creator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,4 @@ export 'src/creator/fields/collapsed_meaning_field.dart';
export 'src/creator/fields/expanded_meaning_field.dart';
export 'src/creator/fields/hidden_meaning_field.dart';
export 'src/creator/fields/tags_field.dart';
export 'src/creator/fields/frequency_field.dart';
4 changes: 4 additions & 0 deletions yuuna/lib/src/creator/anki_mapping.dart
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ class AnkiMapping {
AudioField.key,
PitchAccentField.key,
FuriganaField.key,
FrequencyField.key,
ExpandedMeaningField.key,
CollapsedMeaningField.key,
AudioSentenceField.key,
Expand Down Expand Up @@ -114,6 +115,7 @@ class AnkiMapping {
ContextField.key: {0: ClearFieldEnhancement.key},
PitchAccentField.key: {0: ClearFieldEnhancement.key},
FuriganaField.key: {0: ClearFieldEnhancement.key},
FrequencyField.key: {0: ClearFieldEnhancement.key},
CollapsedMeaningField.key: {0: ClearFieldEnhancement.key},
ExpandedMeaningField.key: {0: ClearFieldEnhancement.key},
HiddenMeaningField.key: {0: ClearFieldEnhancement.key},
Expand Down Expand Up @@ -160,6 +162,7 @@ class AnkiMapping {
ContextField.key: {0: ClearFieldEnhancement.key},
PitchAccentField.key: {0: ClearFieldEnhancement.key},
FuriganaField.key: {0: ClearFieldEnhancement.key},
FrequencyField.key: {0: ClearFieldEnhancement.key},
CollapsedMeaningField.key: {0: ClearFieldEnhancement.key},
ExpandedMeaningField.key: {0: ClearFieldEnhancement.key},
HiddenMeaningField.key: {0: ClearFieldEnhancement.key},
Expand All @@ -182,6 +185,7 @@ class AnkiMapping {
static const List<String> defaultCreatorCollapsedFieldKeys = [
TagsField.key,
FuriganaField.key,
FrequencyField.key,
PitchAccentField.key,
];

Expand Down
119 changes: 119 additions & 0 deletions yuuna/lib/src/creator/fields/frequency_field.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import 'dart:math';

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:yuuna/creator.dart';
import 'package:yuuna/dictionary.dart';
import 'package:yuuna/models.dart';

/// Returns the frequency of a [DictionaryHeading] (uses harmonic mean for
/// multiple entries, idea taken from @MarvNC).
class FrequencyField extends Field {
/// Initialise this field with the predetermined and hardset values.
FrequencyField._privateConstructor()
: super(
uniqueKey: key,
label: 'Frequency',
description: 'Adds frequency of headword for sorting purposes,'
' calculated using the harmonic mean.',
icon: Icons.insert_chart,
);

/// Get the singleton instance of this field.
static FrequencyField get instance => _instance;

static final FrequencyField _instance = FrequencyField._privateConstructor();

/// The unique key for this field.
static const String key = 'frequency';

/// Returns the frequency, set [useMinInDictionary] to true to only use the
/// lower value if one dictionary provides multiple values.
static String getFrequency({
required AppModel appModel,
required DictionaryHeading heading,
required SortingMethod sortBy,
required bool useMinInDictionary,
}) {
List<Dictionary> dictionaries = appModel.dictionaries;

List<String> unhiddenDictionaries = dictionaries
.where((d) => !d.isHidden(appModel.targetLanguage))
.map((d) => d.name)
.toList();

List<(double, String)> unhiddenFrequencies = heading.frequencies
.where((entry) =>
unhiddenDictionaries.contains(entry.dictionary.value!.name))
.map((freq) => (freq.value, freq.dictionary.value!.name))
.toList();

List<double> frequencies = useMinInDictionary
? []
: unhiddenFrequencies.map((tup) => tup.$1).toList();

if (useMinInDictionary) {
Map<String, double> dictionariesPlusFreq = {};
for (var tup in unhiddenFrequencies) {
var entry = dictionariesPlusFreq[tup.$2];
dictionariesPlusFreq[tup.$2] =
entry == null ? tup.$1 : min(entry, tup.$1);
}
frequencies = dictionariesPlusFreq.values.toList();
}

unhiddenFrequencies.map((tup) => tup.$1).toList();

if (frequencies.isEmpty) {
return '';
}

double ret;

switch (sortBy) {
case SortingMethod.harmonic:
ret = frequencies.length /
frequencies.fold(0, (prev, freq) => (1 / freq) + prev);
break;
case SortingMethod.min:
ret = frequencies.reduce((f1, f2) => f1 < f2 ? f1 : f2);
break;
case SortingMethod.avg:
ret = frequencies.fold(0, (prev, freq) => prev + freq.toInt()) /
frequencies.length;
break;
}

return ret.round().toString();
}

@override
String? onCreatorOpenAction({
required BuildContext context,
required WidgetRef ref,
required AppModel appModel,
required CreatorModel creatorModel,
required DictionaryHeading heading,
required bool creatorJustLaunched,
required String? dictionaryName,
}) {
return getFrequency(
appModel: appModel,
heading: heading,
sortBy: SortingMethod.harmonic,
useMinInDictionary: true,
);
}
}

/// The method by which the frequency value is calculated.
enum SortingMethod {
/// DEFAULT: The harmonic mean of frequencies.
harmonic,

/// The smallest frequency value
min,

/// The average frequency value
avg
}
3 changes: 2 additions & 1 deletion yuuna/lib/src/dictionary/dictionary_frequency.dart
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ class DictionaryFrequency {
final IsarLink<Dictionary> dictionary = IsarLink<Dictionary>();

@override
bool operator ==(Object other) => other is DictionaryPitch && id == other.id;
bool operator ==(Object other) =>
other is DictionaryFrequency && id == other.id;

@override
int get hashCode => id.hashCode;
Expand Down
4 changes: 4 additions & 0 deletions yuuna/lib/src/models/app_model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ final List<Field> globalFields = List<Field>.unmodifiable(
AudioSentenceField.instance,
PitchAccentField.instance,
FuriganaField.instance,
FrequencyField.instance,
ContextField.instance,
ExpandedMeaningField.instance,
CollapsedMeaningField.instance,
Expand Down Expand Up @@ -879,6 +880,9 @@ class AppModel with ChangeNotifier {
FuriganaField.instance: [
ClearFieldEnhancement(field: FuriganaField.instance),
],
FrequencyField.instance: [
ClearFieldEnhancement(field: FrequencyField.instance),
],
CollapsedMeaningField.instance: [
ClearFieldEnhancement(field: CollapsedMeaningField.instance),
TextSegmentationEnhancement(field: CollapsedMeaningField.instance),
Expand Down

0 comments on commit 61a243e

Please sign in to comment.