Skip to content

Commit

Permalink
Switch to TreeSets instead of Lists
Browse files Browse the repository at this point in the history
  • Loading branch information
FauconSpartiate committed Jun 2, 2024
1 parent 1538a0e commit 5607c48
Show file tree
Hide file tree
Showing 21 changed files with 1,529 additions and 931 deletions.
41 changes: 30 additions & 11 deletions lib/calculations/calculator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,23 @@ import "package:collection/collection.dart";
// Project imports:
import "package:graded/calculations/calculation_object.dart";
import "package:graded/calculations/manager.dart";
import "package:graded/calculations/subject.dart";
import "package:graded/calculations/test.dart";
import "package:graded/misc/default_values.dart";
import "package:graded/misc/enums.dart";
import "package:graded/misc/storage.dart";
import "package:graded/ui/utilities/ordered_collection.dart";

class Calculator {
static void sortObjects(
List<CalculationObject> data, {
static List<T> sortObjects<T extends CalculationObject>(
Iterable<T> data, {
required int sortType,
int? sortModeOverride,
int? sortDirectionOverride,
List<CalculationObject>? comparisonData,
}) {
if (data.length < 2) return;
if (data.length < 2) return data.toList();

final List<T> result = data.toList();

final int sortDirection = sortDirectionOverride ?? getPreference<int>("sort_direction$sortType");
int sortMode = getPreference<int>("sort_mode$sortType");
Expand All @@ -31,7 +34,7 @@ class Calculator {
switch (sortMode) {
case SortMode.name:
insertionSort(
data,
result,
compare: (a, b) {
int result = compareNatural(a.asciiName, b.asciiName);
if (result == 0) {
Expand All @@ -42,7 +45,7 @@ class Calculator {
);
case SortMode.result:
insertionSort(
data,
result,
compare: (a, b) {
if (a.result == null && b.result == null) {
return 0;
Expand All @@ -56,17 +59,17 @@ class Calculator {
},
);
case SortMode.coefficient:
insertionSort(data, compare: (a, b) => sortDirection * a.weight.compareTo(b.weight));
insertionSort(result, compare: (a, b) => sortDirection * a.weight.compareTo(b.weight));
case SortMode.custom:
final compare = comparisonData ?? getCurrentYear().termTemplate;
data.sort((a, b) {
final OrderedCollection<CalculationObject> compare = getCurrentYear().comparisonData;
result.sort((a, b) {
return compare.indexWhere((element) => a.name == element.name) - compare.indexWhere((element) => b.name == element.name);
});
case SortMode.timestamp:
if (data.first is! Test) throw UnimplementedError("Timestamp sorting is only implemented for tests");
if (result.first is! Test) throw UnimplementedError("Timestamp sorting is only implemented for tests");

insertionSort(
data,
result,
compare: (a, b) {
int result = (a as Test).timestamp.compareTo((b as Test).timestamp);
if (result == 0) {
Expand All @@ -78,6 +81,8 @@ class Calculator {
default:
throw const FormatException("Invalid");
}

return result;
}

static double? calculate(
Expand Down Expand Up @@ -175,4 +180,18 @@ class Calculator {

return result;
}

static List<Test> getSortedTestData(List<Test> tests) {
return sortObjects<Test>(tests, sortType: SortType.test);
}

static (List<Subject>, List<List<Subject>>) getSortedSubjectData(List<Subject> subjects) {
final List<Subject> subjectData = sortObjects<Subject>(subjects, sortType: SortType.subject);
final List<List<Subject>> childrenData = subjectData.map((element) {
if (element.children.isEmpty) return <Subject>[];
return sortObjects<Subject>(element.children, sortType: SortType.subject);
}).toList();

return (subjectData, childrenData);
}
}
123 changes: 61 additions & 62 deletions lib/calculations/manager.dart
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
// Flutter imports:
import "package:flutter/material.dart";

// Package imports:
import "package:collection/collection.dart";

// Project imports:
import "package:graded/calculations/subject.dart";
import "package:graded/calculations/term.dart";
Expand All @@ -12,10 +9,10 @@ import "package:graded/calculations/year.dart";
import "package:graded/localization/translations.dart";
import "package:graded/main.dart";
import "package:graded/misc/compatibility.dart";
import "package:graded/misc/enums.dart";
import "package:graded/misc/setup_manager.dart";
import "package:graded/misc/storage.dart";
import "package:graded/ui/utilities/hints.dart";
import "package:graded/ui/utilities/ordered_collection.dart";

class Manager {
static List<Year> years = [];
Expand Down Expand Up @@ -48,7 +45,7 @@ class Manager {
static void calculate() {
getCurrentYear().calculate();

sortAll();
serialize();
}

static void clearTests() {
Expand All @@ -74,7 +71,6 @@ class Manager {
year.name = getHint(translations.yearOne, years);
years.add(year);
changeYear(years.length - 1);
year.sort();
}

static void changeYear(int index) {
Expand All @@ -83,37 +79,10 @@ class Manager {
calculate();
}

static void sortAll({int? sortModeOverride, int? sortDirectionOverride}) {
getCurrentYear().sort(sortModeOverride: sortModeOverride, sortDirectionOverride: sortDirectionOverride);

for (final Subject element in getCurrentYear().termTemplate) {
element.sort(sortModeOverride: sortModeOverride, sortDirectionOverride: sortDirectionOverride);
}

getCurrentYear().sortTermTemplate(
sortModeOverride: sortModeOverride,
sortDirectionOverride: sortDirectionOverride,
);

if (sortModeOverride == null && sortDirectionOverride == null) {
serialize();
}
}

static Term refreshYearOverview({Term? yearOverview, Year? year}) {
yearOverview ??= getYearOverview();
year ??= getCurrentYear();

sortAll(
sortModeOverride: SortMode.name,
sortDirectionOverride: SortDirection.ascending,
);

yearOverview.sort(
sortModeOverride: SortMode.name,
sortDirectionOverride: SortDirection.ascending,
);

for (final subject in yearOverview.subjects) {
subject.tests.clear();
for (final child in subject.children) {
Expand Down Expand Up @@ -158,39 +127,10 @@ class Manager {
}

yearOverview.calculate();
sortAll();
yearOverview.sort();

return yearOverview;
}

//TODO make more use of this function
static List<Subject> getSubjectAcrossTerms(Subject subject) {
final List<Subject> result = [];

for (final term in getCurrentYear().terms) {
final Subject? s = getSubjectInTerm(subject, term);
if (s == null) continue;
result.add(s);
}
return result;
}

static Subject? getSubjectInTerm(Subject? subject, Term term) {
if (subject == null) return null;

final Subject? result = term.subjects.firstWhereOrNull((s) => s.name == subject.name);

if (result != null) return result;

for (final s in term.subjects) {
final Subject? child = s.children.firstWhereOrNull((c) => c.name == subject.name);
if (child != null) return child;
}

throw ArgumentError("Subject not found in term");
}

Map<String, dynamic> toJson() => {
"years": years,
};
Expand Down Expand Up @@ -231,3 +171,62 @@ Term createYearOverview({required Year year}) {
Term getCurrentTerm() {
return getTerm(Manager.currentTerm);
}

//TODO make more use of this function
List<Subject> getSubjectAcrossTerms(Subject subject) {
final List<Subject> result = [];
final (int, int?) indexes = getSubjectIndex(subject);

for (final term in getCurrentYear().terms) {
final Subject s = indexes.$2 == null ? term.subjects[indexes.$1] : term.subjects[indexes.$1].children[indexes.$2!];
result.add(s);
}
return result;
}

Subject? getSubjectInTerm(Subject? subject, Term term) {
if (subject == null) return null;

final (int, int?) indexes = getSubjectIndex(subject);

if (indexes.$2 == null) {
return term.subjects[indexes.$1];
} else {
return term.subjects[indexes.$1].children[indexes.$2!];
}
}

(int, int?) getSubjectIndex(Subject subject, {Term? term, bool? inTermTemplate, bool? inComparisonData, bool? isChild}) {
final List<OrderedCollection<Subject>> lists = [];

if (term != null) {
lists.add(term.subjects);
} else if (inComparisonData != null && inComparisonData) {
lists.add(getCurrentYear().comparisonData);
} else {
if (inTermTemplate == null || inTermTemplate) {
lists.add(getCurrentYear().termTemplate);
}
if (inTermTemplate == null || !inTermTemplate) {
for (final term in getCurrentYear().terms) {
lists.add(term.subjects);
}
lists.add(getYearOverview().subjects);
lists.add(getCurrentYear().comparisonData);
}
}

for (final subjects in lists) {
if (isChild == null || !isChild) {
final int result1 = subjects.indexOf(subject);
if (result1 != -1) return (result1, null);
}

for (int j = 0; j < subjects.length; j++) {
final int result2 = subjects[j].children.indexOf(subject);
if (result2 != -1) return (j, result2);
}
}

throw ArgumentError("Subject not found in terms");
}
56 changes: 22 additions & 34 deletions lib/calculations/subject.dart
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
// Package imports:
import "package:collection/collection.dart";

// Project imports:
import "package:graded/calculations/calculation_object.dart";
import "package:graded/calculations/calculator.dart";
import "package:graded/calculations/manager.dart";
import "package:graded/calculations/test.dart";
import "package:graded/misc/default_values.dart";
import "package:graded/misc/enums.dart";
import "package:graded/ui/utilities/ordered_collection.dart";

class Subject extends CalculationObject {
List<Subject> children = [];
OrderedCollection<Subject> children = OrderedCollection.newTreeSet();
List<Test> tests = [];
@override
double get denominator => getCurrentYear().maxGrade;
Expand Down Expand Up @@ -51,44 +48,33 @@ class Subject extends CalculationObject {
}
}

void removeTest(int position, {bool calculate = true}) {
tests.removeAt(position);
void removeTest(Test test, {bool calculate = true}) {
tests.remove(test);
if (calculate) {
Manager.calculate();
}
}

void editTest(int position, double numerator, double denominator, String name, double weight, {bool isSpeaking = false, int? timestamp}) {
final Test t = tests[position];

t.numerator = numerator;
t.denominator = denominator;
t.name = name;
t.weight = weight;
t.isSpeaking = isSpeaking;
t.result = Calculator.calculate([t], clamp: false);
t.timestamp = timestamp ?? t.timestamp;
Manager.calculate();
}

void sort({int? sortModeOverride, int? sortDirectionOverride}) {
Calculator.sortObjects(
children,
sortType: SortType.subject,
sortModeOverride: sortModeOverride,
sortDirectionOverride: sortDirectionOverride,
comparisonData: children.isNotEmpty ? getCurrentYear().termTemplate.firstWhereOrNull((element) => element.name == name)?.children : null,
);

for (final Subject element in children) {
element.sort(sortModeOverride: sortModeOverride, sortDirectionOverride: sortDirectionOverride);
void removeTestAt(int position, {bool calculate = true}) {
tests.removeAt(position);
if (calculate) {
Manager.calculate();
}
}

Calculator.sortObjects(tests, sortType: SortType.test, sortModeOverride: sortModeOverride, sortDirectionOverride: sortDirectionOverride);
void editTest(Test test, double numerator, double denominator, String name, double weight, {bool isSpeaking = false, int? timestamp}) {
test.numerator = numerator;
test.denominator = denominator;
test.name = name;
test.weight = weight;
test.isSpeaking = isSpeaking;
test.result = Calculator.calculate([test], clamp: false);
test.timestamp = timestamp ?? test.timestamp;
Manager.calculate();
}

Subject.fromSubject(Subject subject) {
children = subject.children.map((e) => Subject.fromSubject(e)).toList();
children = OrderedCollection.newTreeSet(subject.children.map((e) => Subject.fromSubject(e)));
isGroup = subject.isGroup;
isChild = subject.isChild;
speakingWeight = subject.speakingWeight;
Expand All @@ -103,7 +89,7 @@ class Subject extends CalculationObject {
}
if (json["children"] != null) {
final childrenList = json["children"] as List;
children = childrenList.map((childJson) => Subject.fromJson(childJson as Map<String, dynamic>)..isChild = true).toList();
children = OrderedCollection.newTreeSet(childrenList.map((childJson) => Subject.fromJson(childJson as Map<String, dynamic>)..isChild = true));
}

isGroup = json["type"] != null && json["type"] as bool;
Expand All @@ -126,4 +112,6 @@ class Subject extends CalculationObject {
"children": children.toList(),
"tests": tests,
};

int compareTo(Subject other) => name.hashCode - other.name.hashCode;
}
Loading

0 comments on commit 5607c48

Please sign in to comment.