habitrack/docs/4-Implementation.md
2024-08-26 00:34:20 +02:00

3.5 KiB

Implementation

Unsere Code-Struktur ist im Laufe der Entwicklung mehrere Wandel durchlaufen. Die Erste Version ist durch Folgendes UML-Klassendiagramm dargestellt:

Erstes Design

UFD

Dieses Modell verwendet eine Abstrakte Widget-Basisklasse, von der die Einzelnen Funktionswidgets erben. Sie ist mit Einigen Basisfunktionen versehen, die teilweise noch nicht implementiert werden. Die Build-Funktion baut alle Teile des Widgets, die alle Funktions-Widgets gemein haben: Die Aufklappbare Progress-Bar, den Widget-Titel und das Einstellungsmenu.

Um die Einstellungen Anpassen zu können, gibt es die Klasse WidgetSettings. Davon wird eine in WidgetBase gespeichert. WidgetSettings besteht aus einer Liste an SettingEntries. Dieses Design wurde aus einem Projekt für die Arbeit genommen, in dem eine Einfache GUI in TKInter Programmiert wurde. SettingEntries ist ein Interface mit der Build-Methode, sowie Value Gettern/Settern. Die einzelnen Subklassen stellen verschiedene Einstellungstypen dar: Eingabe von einem Datum, von Text, von Zahlen, oder von Zahlen in einem Raum mit einem Slider. WidgetSettings war in diesem Design der Primäre Ort, in dem die Widget-Einstellungen gespeichert wurden, und es wurde über eine Map von String auf SettingEntry auf sie zugegriffen.

Jedes Funktionswidget hat ein Content-Widget, in welchem der Teil des Widgets gebaut wird, der erscheint, wenn man das Widget aufklappt.

Diese Klassenstruktur war gut, um Redundanzen im Code zu minimieren. Allerdings war sie auch etwas überkompliziert, und hatte die Persistenz über Sembast und das State Management mit Riverpod noch nicht wirklich mit einberechnet. Dies hat zu einigen Fehlern geführt, weswegen sie überarbeitet wurde.

Zweites Design

UFD

Das Zweite Design ist eine Menge der Komplexität des Ersten Designs losgeworden. Die Funktionswidgets erben nicht mehr von einer Gemeinsamen Basisklasse, enthalten dafür aber eine Menge duplizierten Code. Dadurch, dass alles in einer Klasse gemanaged wird, wird die Persistenz erleichert.

Jedes Funktionswidget hat nun ein zugehöriges Item, welches den State des Widgets speichert. Dazu gehören die Einstellungen, der Fortschritt, und alles was sonst benötigt wird. Diese Items können über ein Riverpod-Provider aus der Sembast-Datenbank geholt und dahin auch wieder gespeichert werden.

Was gut und weniger Gut lief

Im Laufe der Programmierung wurden wir mit Flutter und Dart immer mehr vertraut, was es uns ermöglicht hat, Dinge zu implementieren, die am Anfang unmöglich erschienen. Allerdings wurden deswegen am Anfang Designentscheidungen getroffen, die uns viel Zeit gekostet haben und so im Endeffekt nicht funktionierten. Zwar haben wir viel dabei gelernt, trotzdem war die Zeit eine sehr wertvolle Ressource. Es gab demnach einige Probleme mit der Persistenz-Machung unseres Ursprünglichen Designs, weswegen vieles überholt werden musste. Da Sembast keine Widgets direkt speichern können, müssen die State als getrennte Objekte gespeichert werden. Dann müssen die Widgets die state vom Datenbank laden und die jeweilige Daten populieren. Wir hatten auch Probleme bei dem generierung von .g.dart Dateien mit freezed; das hat eine Weile gedauert, vor wir es lösen könnten. Sembast war danach relativ einfach anzuwenden, allerdings müssten wir "hacky" methoden manchmals verwenden, wie z.b. die Speicherung vom individuelle task items als Strings, da wir nicht composition mit freezed zum laufen bringen können.