Eine Email-Client-App entwickeln

Noah Vogt & Simon Hammer Klasse 4cg Victor Yakhontov & Daniel Bühler

Geschrieben im Jahr 2021

Noah Vogt & Simon Hammer  INHALTSVERZEICHNIS

Inhaltsverzeichnis

1 Vorwort 2

2 Einleitung 2 2.1 Arbeitsziele . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 2.2 Arbeitskonzept . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3

2.2.1 Quellcode Modell . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 2.2.1.1 Permissive Licenses . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 2.2.1.2 Copyleft Licenses . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4

2.2.2 Philosophie (suckless) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5

2.2.2.1 Hintergründe, Technologisch, UNIX, KISS . . . . . . . . . . . . . . . . . . 5 2.2.3 Lizensierung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5

3 Arbeitsprozess 5 3.1 Programmiermittel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 3.2 Programmstruktur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6

3.2.1 Sicherheit / Security (Features) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 3.2.2 Code Kompaktheit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 3.2.3 Maintaining . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 3.2.4 less bug/error-prone . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 3.2.5 Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 3.2.6 Recyclerviewer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 3.2.7 Popup Window . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 3.2.8 Database . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9

3.2.8.1 MessageDao . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 3.2.9 Repository/ViewModel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 3.2.10 Draft Messages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13

3.3 Umsetzung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 3.3.1 Bugs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 3.3.2 Probleme / Hiccups . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 3.3.3 Kommunikation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13

3.4 Testing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14

4 Resultate 14 4.1 Vergleich mit unseren ursprünglichen Zielen . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 4.2 Vergleich mit der Konkurrenz . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 4.3 Beschreibung der vorliegenden getesteten Funktionalitäten . . . . . . . . . . . . . . . . . . . 14 4.4 Vor- und Nachteile unserer App . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14

4.4.1 Pro . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 4.4.2 Kontra . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14

5 Selbstreflexion 14 5.1 Was Gut Lief . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 5.2 Was Schlecht Lief . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 5.3 Was Wir Gleich Machen Würden . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 5.4 Was Wir Anders Machen Würden . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 5.5 abschliessende persönliche Schlussfolgerung . . . . . . . . . . . . . . . . . . . . . . . . . . 15

Noah Vogt & Simon Hammer  2 EINLEITUNG

6 Danksagung 15 Free Software Foundation

1 Vorwort

Noah hatte schon länger grosses Interesse am Programmieren. Ich hingegen begann Interesse an den Programmiersprachen zu entwickeln als wir im Unterricht Python lernten. Als die Zeit kam sich für ein Maturthema zu entscheiden, war für mich klar, ich würde eine App programmieren. Anfangs ging es mir darum eine nützliche App zu kreieren, welche ich selbst verbessern kann und meine Bedürfnisse perfekt abdeckt. Zu diesem Zeitpunkt störte es mich, dass es keine effiziente Edubs-Mail-App fürs Smartphone gab und ich wollte Sie selbst kreieren. Da ich aber wusste, dass ich mich nicht so gut auskenne, fragte ich bei Noah nach, wie er die Idee findet und ob er vielleicht mit mir diese Arbeit angehen würde. Er war der Meinung, dass wir eine solche App auch für alle Emailanbieter erstellen können. Wir haben uns dann Konkreter über die App unterhalten und entschieden, diese auch zu Zweit zu Programmieren. Wir waren uns einig eine App zu erstellen, welche keine Schwierigkeiten machte, wenn sie auf älteren Geräten lief - schliesslich hatte noch z.Z. auch nur ein sehr altes Android Gerät - und sie sollte Open Source sein. Dafür sprechen viele praktische und philosphisch-ethische Gründe, aber dazu später mehr. Bei den Funktionen waren wir uns sehr einig und wir hatten eine Menge an Ideen um einen vollumfänglichen Emailclient zu erstellen. Das Design liessen wir zu beginn zu Seite, da wir es schlicht und funktional halten wollten. Wir hatten beide eine gewisse Vorstellung unserer App vor uns und ob wir diese erreicht haben wird sich im laufe dieser Arbeit herausstellen.

2 Einleitung

Das Kommunikationsmittel Email ist auch nach seinem fünfzigjährigen Geburtstag noch rege im Alltagsgebrauch vieler Leute in den meisten Ländern. Nach dem Prinzip des technologischen Fortschrittes könnte angenommen werden, dass sich auch in den letzten zehn Jahren - nämlich seit dem Aufkommen der massentauglichen Smartphones - die Emailsoftware verbessert hat. Doch auf dem Smartphone war es für uns, die Ersteller dieser Maturarbeit, schwer einen guten Email Client zu finden. Diese Maturarbeit ist unser Teil, daran etwas zu ändern, wenigstens für unseren persönlichen Gebrauch.

2.1 Arbeitsziele

Wir wissen, was ein Email Client können muss, und haben nicht vor eine Apps zu designen, welche vollkommen überladen ist mit Funktionen, die keiner braucht.

Die App soll die Basisfunktionen eines klassischen Email-Clients erfüllen. Dazu gehören das Lesen und Schreiben von Emails, das Öffnen und Anfügen von Anlagen, die Setzung einer Email-Signatur und das Erstellen und Speichern von Entwürfen. Ebenso soll es verschiedene Ordner unterstützen, wie z.B. ein Spam/Junk oder ein Archiv Ordner. Dazu soll es möglich sein E-Mails visuell sortieren zu können, beispielsweise indem die Ordner im Client nach Datum des Empfangs oder dem Absender sortiert werden können. E-Mails sollen mit markiert, gelöscht und weitergeleitet werden können. Es soll eine Suchfunktion für jeden Mailordner geben.

Ebenso soll es einen Account Manager geben, was voraus setzt, dass es möglich ist sich mit verschiedenen Accounts anzumelden und diese bei bedarf zu wechseln. Beim Anmelden einer E-Mail soll es dem Nutzer leicht gemacht werden mit eingebauten Konfigurationen für beliebte Emailprovider in der Schweiz. Darunter diese Anbieter: stud.edubs.ch, gmail.com, gmx.ch, outlook.com, yahoo.com, icloud.com, hotmail.com, web.de.

Ein Element, welches fast jede App Heutzutage hat, sind Pushnachrichten, welche auch eingebaut werden sollen. Dabei sollen neue Nachrichten mit dem Absender und dem Beginn der E-Mail angezeigt werden. Dies soll ein weiteres Feature der App sein. Wie es für leichte Email-Clients oft üblich ist, werden Bilder erst angezeigt, sobald es der Nutzer ausdrücklich möchte. Dieses Verhalten soll in den App-Einstellungen steuerbar gemacht werden. Eine sehr praktische Funktion soll sein, dass E-Mail-Adressen gespeichert werden und beim schreiben einer neuen E-Mail direkt verfügbar sind und ausgewählt werden können. Ob diese Funktion sinnvoll ist, ist fraglich, da auf viele Leute keine Emailaddressen auf der Kontaktapp ihres Handys speichern.

Das letzte Feature soll sein, dass Links direkt in einem Browser geöffnet werden können. Die Einstellungen sollen zudem das Farblayout der App ändern können, die Synchronisationsintervalle ändern können, Einstellungen an den Pushnachrichten ändern können, Kontaktlisten verwalten und Einstellungen zu Privatsphäre beinhalten. Im Unterschied zur Konkurrenz soll diese App so programmiert werden, dass sie alle nötigen Grundfunktionen für einen Email Client auf dem Smartphone beinhaltet, aber schneller starten soll als die Apps der Konkurrenz, weniger Speicherplatz und Resourcen verbrauchen soll und nicht mit unnötigen Funktionen überladen sein.

Ein Pluginmanager soll auch eingebaut werden, um weitere Funktionen, welche das Programm verlangsamen würden oder nicht für jedermann geeignet sind, hinzuzufügen können. Es existiert natürlich auch die Möglichkeit nach Abschluss dieser Arbeit die App zu verbessern und auf uns an Nutzerwünsche anzupassen, doch hier wurden jetzt die ungefähren, geplanten Grundfunktionen genannt, um die Ziele der Funkionalität besser zu beleuchten. Wir haben uns viele Ziele gesetzt und dachten, dass wir auch mehr schaffen können. Weshalb dies nicht der Fall ist wird noch genauer betrachtet.

2.2 Arbeitskonzept

2.2.1 Quellcode Modell

Um ein Programm zu programmieren, werden menschenlesbare Instruktionen in ein oder mehrere Textdateien geschrieben, die dann in Sprache, welche die Computerhardware interpretieren und ausführen zu kann, übersetzt.

Abbildung 1: Quellcode (engl. “source code”) wird in ausführbaren Maschinencode umgewandelt [SGF02]

Hier als Beispiel der Source Code zu einem simplen Programm helloworld.c geschrieben in der Programmiersprache C, welches in der Konsole ein simples “Hello World” ausgibt:

#include <stdio.h>
int main() {
    printf("Hello World\n");
    return 0;

}

Ein Teil der kompilierten, ausführbaren Version des Programmes ./helloworld sieht aber so aus:

0011010001100000010111110110111101101100011001110110001001101111011011000110000101100100010
1111101101111011101000111001101110010011000010101111100000000000000110100011100000111100001
1101010110001100000000011011010110111101101100011100000111010001100101011001000110010100110
0000010111001011111000000000000000000000011010010000000011001000101111101011111011011110110
1100011001110110001001101111011011000110000101100100010111110110111101110100011100110111001
0000000000000001101001001000001100001010111110111100001110101011001100101111101101110011010

Wie man sieht, geht bei diesem Prozess des Kompilierens die Lesbarkeit für den Menschen grösstenteils verloren. Um ein Programm ausführen können braucht der Nutzer also keinen Zugang zum Quellcode. Doch wenn er wissen will, was das Programm macht - es könnte ihn ausspionieren oder andere bösartige Sachen im Hintergrund machen - oder einfach das Programm verändern will, braucht er unbedingt Zugang zum Source Code.

Doch auch bei Open Source Software gibt es verschiedene Lizenzmodelle welche gewählt werden können. Diese lassen sich ziemlich gut in zwei Kategorien unterteilen:

2.2.1.1 Permissive Licenses

Mit diesen Lizenzen hat man das Recht das Programm für JEDEN Zweck zu benutzen, den Source Code zu lesen, ändern und seine Änderungen zu veröffentlichen. Ihr Name kommt von der Tatsache, dass sie “permissiv” sind, wenn es um ihre wenigen Einschränkungen geht: Sie schränken die Verbreitung des Quellcodes nicht sehr stark ein und erlauben es oft, die Software unter JEGLICHEN Bedingungen weiterzugeben. Das bedeutet es ist möglich, den Fork eines permissiv lizenzierten Programms proprietär zu machen.

Das bedeutet, dass Sie den Code nicht davor schützen, in anderen Projekten, selbst wenn diese proprietär sind, verwendet zu werden, ohne etwas zurückzugeben zu müssen. Das ist ein eindeutiger Nachteil und der Grund, warum manche Leute - meist auf Imageboards [Ano20] - diese Lizenzen als “Cuck Licenses” beschimpfen, hier ein populäres Argument aus einem Blogpost:

When you release any code under a Cuck License, you are simply writing free commercial code for corporations that will inevitably use it against you. You might as well just actually get a job with them so you can get paid for what you do instead of just getting cucked.

— Luke Smiths Blogpost [Smi21]

Ein positiver Punkt von diesen Lizenzen ist aber ihre Einfachheit: Die MIT-Lizenz zum Beispiel besteht aus nur 20 SLOC, während eine Copyleft Lizenz wie die GPL v3 aus mehr als 600 SLOC und gewissem Juristenjargon besteht und daher viel schwerer zu verstehen ist.

2.2.1.2 Copyleft Licenses

Wie bei permissiven Lizenzen können Sie das Programm für JEDEN Zweck ausführen, den Quellcode lesen, ändern und die Änderungen zu veröffentlichen. Der Trick liegt jedoch in den restriktiven Redistributionsbedingungen: Sie dürfen das Programm NUR verbreiten, wenn Ihre Version die gleichen Freiheiten bietet. Dies geschieht in der Regel dadurch, dass die Weitergabe nur unter der gleichen Lizenz erlaubt ist.

Der Name “copyleft” ist eine offensichtliche Anspielung auf das Wort “Copyright”, da es versucht, dessen Konzept genau umzukehren: Anstatt die nahezu weltweit vorhandenen Kopierrechtsgesetze dazu zu verwenden, Nutzerfreiheiten einzuschränken, werden Copyleft-Lizenzen dazu eingesetzt diese zu bewahren und erweitern. [Kum11]

Wie bereits erwähnt, müssen solche Lizenzen eine Menge juristischen Jargon enthalten, um die vorhandene Gesetzeslage des Kopierrechts auszunutzen. Dies macht die Lizenz um einiges komplexer in Länge und an Verständlichkeit. Viele Unterstützer des Free Software Movements ziehen es aber trotzdem vor Copyleft Lizenzen zu verwenden, sofern möglich, da sie sicherstellen, dass die Freiheiten für immer gewährt werden müssen und die Hersteller von proprietärem Code daran hindert, von ihrem geschriebenen freien Code zu profitieren.

2.2.2 Philosophie (suckless)

Many (open source) hackers are proud if they achieve large amounts of code, because they believe the more lines of code they’ve written, the more progress they have made. The more progress they have made, the more skilled they are. This is simply a delusion.

Noah Vogt & Simon Hammer  3 ARBEITSPROZESS

— https://suckless.org Manifest [suc21]

Eine grosse Anzahl Open-Source-Entwickler stolz darauf, Software mit scheinbar möglichst vielen Features zu schreiben. Dies führt zu einer großen Codebasis, die mit jedem Release größer und größer wird. Dadurch wird es schwieriger, die ständig wachsende Codebasis zu unterhalten, es treten immer mehr Fehler auf, die Sicherheit und - vor allem - die Leistung leidet unter diesen Bedingungen. Dies führt zu einer Verschlechterung der Code-Qualität der Software, da es die gängige Praxis ist, “Zeit und Geld zu sparen”. [BGV20]

Hier kommt die Philosophie des Suckless Philosphy ins Spiel: Sie zielt darauf ab, Software mit Hinblick auf Einfachheit zu entwickeln: Weniger Quellcodezeilen, um das Projekt nicht in ähnlicher Weise unmaintainable zu machen, wie oben erwähnt. Diese Art zu programmieren ist viel schwieriger, aber der Aufwand ist es meistens wert. Diese Programmierphilosophie bietet auch Anreize für das qualitativ hochwertige Neuschreiben von Programmen - was bei der sogenannten Bloated Software [BGV20] viel seltener vorkommt - und gibt dem Benutzer mehr Alternativen zur Auswahl.

2.2.2.1 Hintergründe, Technologisch, UNIX, KISS

Die Suckless Philosophie ist aber längst nicht die erste Philosophie im Softwarebereich welche auf Simplizität beruht; so beispielsweise eine beliebte Definition der altbekannten UNIX Philosphy:

This is the Unix philosophy. Write programs that do one thing and do it well. Write programs to work together. Write programs that handle text streams, because that is a universal interface.

— A Quarter Century Of UNIX [Sal94]

Bekannt ist auch das KISS Prinzip: “Keep it simple, stupid”. Dieses Prinzip kommt ursprünglich vom U.S. Admiral Stroop, der das “Project KISS” 1960 ins Leben gerufen hatte, welches die Verlässlichkeit verbessern und die Kosten für amerikanische Militärausrüstungen senken soll. [DP09] Gerne wird diese Prinzip zitiert, wenn jemand der Meining ist, unnötige Komplexität sei vorhanden in einem Softwareprojekt.

2.2.3 Lizensierung

Die Unterschiede zwischen verschiedenen Source-Code Modellen und deren Lizenzierung wurden bereits besprochen. Für dieses Softwareprojekt wurde sich entschieden die GNU General Public License (GPL) Version 3 [Sta07] der Free Software Foundation zu verwenden, da diese eine der bekanntesten, strengsten und somit effektivsten Copyleft-Lizenzen ist.

3 Arbeitsprozess

3.1 Programmiermittel

Um ein Programm zu Entwickel mit einem solchen Umfang, braucht es Hilfsmittel die sich auf genau das spezialisiert haben. Um allgemein grosse Programme zu Entwickel sind ”Version Control Systemsëine sehr hilfreiche Methode um Funktionen in ein Programm einzubauen ohne das Risiko das Programm komplett zu Überarbeiten, wenn diese Funktion ein Fehler hervorruft. In diesem Fall wurde Git als VCS genutzt um für jegliche Funktion einen eigenen Branch zu erstellen und diesen wieder mit dem Hauptbranch zu mergen wenn die Funktion fertig ist.

3.2 Programmstruktur

3.2.1 Sicherheit / Security (Features)

In Anbetracht der Tatsache, dass auf 99% der Consumer-Smartphones die Benutzer nicht einmal Root-Zugriff haben (den aber der “Besitzer” der Smartphone-Software hat), würden Leute, die auf Privatsphäre oder Sicherheit bedacht sind, ihre wichtigen Mailboxen ohnehin nicht auf ihrem Smartphone benutzen, sondern eher

Gymnasium Kirschgarten  Seite 6

auf ihrem besser gesicherten Computer, auf dem ein reines Freies-Software-Betriebssystem läuft usw.

wenn man bedenkt, dass das E-Mail-Protokoll in einer Zeit geschrieben wurde, in der der Zugang zu Computern noch sehr eingeschränkt war und Datenschutz und Sicherheit nicht im Sinne seiner Schöpfer waren, ist das durchaus verständlich. Warum es sich bis heute in diesem Zustand gehalten hat, liegt zum einen an den Networking Effects und zum anderen daran, dass die meisten Menschen die technischen Details einfach nicht kennen und/oder sich nicht darum kümmern.

Heutzutage ist es möglich, den Inhalt (Text) einer E-Mail zu verschlüsseln, nicht aber die Metadaten; hier ist die Spezifikation des E-Mail-Protokolls schuld. Dies und die Tatsache, dass es nicht als sichere oder private Art der Nachrichtenübermittlung konzipiert wurde, macht E-Mails für diese Art von Konversation unbrauchbar. Wenn Sie Ihren Freunden neue Pläne für die Übernahme der Welt und die Errichtung einer globalen katholischen Monarchie schicken wollen, ohne dass jemand davon erfährt, sind Sie ein Narr, wenn Sie dafür E-Mails verwenden (zugegeben, das ist ein übertriebenes Beispiel, aber ich hoffe, der Gedanke ist klar).

Die Schlussfolgerung für unser Anwendungsprojekt ist also, unsere Anwendung nicht mit schwer zu verwendenden Sicherheitsfunktionen aufzublähen, die die Anwendung und die Codebasis nur unnötig aufblähen. Es sollten jedoch vernünftige, auf Sicherheit ausgerichtete Standardeinstellungen genutzt werden, die u.a. jetzt näher erläutert werden.

3.2.2 Code Kompaktheit

Das ist etwas, was im Laufe diese Projekts ziemlich gut eingehalten wurde: Es wurden viel weniger SLOC geschrieben als bei den konkurrierenden Email Clients auf Android. Das ist ein sehr wichtiger Massstab um das initiale Ziel der Suckless Philosophy so gut wie möglich zu erreichen. Während dieses Projekt nur ˜4000 SLOC Zeilen Code aufzuweisen hat, sind es bei anderen Apps gar über 300’000 SLOC.

3.2.3 Maintaining

Die Codebasis dieses Projektes sollte sehr einfach zu maintainen sein: Die wichtigsten Punkte dabei sind, dass der Maintainer schaut, dass die Dependencies auf der neusten Version sind und ob sie als obsolet oder veraltet angesehen werden müssten.

Selbst wenn das Projekt aufgegeben werden sollte bei seinen ursprünglichen Entwicklern und jemand das Projekt findet und es ihm gefällt kann er dann recht einfach und schnell die Codebase durchlesen und sie ohne allzu grossen Aufwand verstehen. Wäre das auch der Fall bei bloated Software wie thunderbird? Das glaube ich auch nicht.

3.2.4 less bug/error-prone

Es ist grösstenteils der suckless-basierten Codingphilosophie zu verdanken, aber auch der Umsetzung. Es könnte jedoch der Fall sein, dass schlechte Coding Practices verwendet wurden, da die beiden initialen Entwickler dieses Projekts nur eine beschränkte Erfahrung mit der Androidentwicklung mit der Java-Programmiersprache hatten.

3.2.5 Interface

Noah begann dann dieses Programm leicht auszubauen und fügte einige Interface Inhalte hinzu. Abbildung 2: Drawer Navigation Menu Die App beinhaltete ein Hamburgermenü mit drei Ordnern und einem Knopf, welcher den Nutzer zu einem Popupwindow führte, in welchem es so aussah als würde es möglich sein sich anzumelden. Die Basis für die App wurde gelegt und die beiden entschieden sich mit dem Interface anzufangen.

3.2.6 Recyclerviewer

Simon begann mit der Recherche zum Recyclerviewer. Er war viel im Internet und fand schnell einige Beispiele, welche er ausprobierte und für seinen Nutzen gestaltete. Ein Recyclerviewer ist nicht sehr kompliziert hat aber gewisse Kniffe auf die Simon traf.

Ein Recyclerviewer ist in fünf grundlegende Teile aufgeteilt.

1. Das recyclerview Objekt, welches ein Container ist und in das User Interface eingebaut wird. Es beinhaltet verschiedene Views, welche nochmals unterteilt werden können. In einer View wird in unserem Fall eine Nachricht eingebaut mir dem Absender, der Absende Zeit und einem Betreff.

2. Der Layout manager. Er ist für die form einer einzelnen View verantwortlich. Der Layout manager kann auch wieder in drei Arten unterteilt werden. Der Linearlayout Manager sorgt für eine Horizontale oder vertikale unterteilung einer View. Hingegen führt der Gridlayout Manager zu einer horizontalen und vertikalen Unterteilung des View. Für den Email-Client bietet er die beste oberfläche um Nachrichten darzustellen. Es gibt nämlich noch den den Staggeredgridlayout Manager, welcher für eine versetzen unterteilung der View kann sorgen. Dies ist aber für eine Email-Client unbrauchbar.

Abbildung 3: Layout Manager Recyclerview [Ano]

3. Der View Holder bietet die Möglichkeit jedes einzelne Raster der View mit einem Item auszustatten mit wiederum einer View in einem Recyclerviewer

4. Der Adaper ist wohl eines der wichtigsten Teile des Recyclerviewer. Er sorgt für das erstellen des ViewHolder-Objekt und bindet auch die Daten aus der Database an den View Holder

5. Die Database ist das Herzstück dieser App und wir auch für den Recyclerviewer verwendet um die Views mit den richtig Informationen zu füllen.

Die Wahl des Layout Manager wurde sehr schnell getroffen. Es war klar, dass eine Nachricht nicht nur eine Information auf horizontaler Ebene anzeigen muss sondern z.b auch das Datum nicht versetzt angezeigt werden soll. Weshalb der Gridlayout Manager gewählt wurde. Nun hat sich Simon in einem Tutorial über den Recyclerviewer informiert und konnte sich auch ein beispiel anschauen, woran sich der Recyclerviewer der Email-App zu beginn sehr stark orientierte.

Nach dem sich Simon über den Recyclerviewer informiert hat, sollte er endlich in das Programm eingefügt werden. Leider gab es da einige Probleme. Der erste Versuch scheiterte daran, dass die App abstürzte ohne einen Error zu melden. Und nach einiger Zeit war die beste Lösung wieder an einen Punkt zu gehen, an welchem die noch funktionierte, nur ohne vollständigen Recyclerviewer. Es dauerte einen ganzen Monat bis eine weitere Version mit Recyclerviewer bereit war. Nur diesmal funktionierte die App.

Der Recyclerviewer war an diesem Punkt sehr simpel. Er konnte eine vorbestimmte menge an Views anzeigen, welche in einem Loop generiert wurden, lass die Informationen aus einer sehr simplen Database aus und er konnte noch nicht aktualisiert werden. Die Informationen konnten nur einmal eingelesen werden und der View-Holder wurde in der gleichen Klasse wie der Adapter definiert.

Die Database bestand zu diesem Zeitpunkt aus nur einer Klasse, welche fünf Strings definierte, diese einlesen konnte und auch wieder ausgeben konnte. Mit dieser Klasse wurde ein Objekt erstellt, welches in einer Arraylist, durch einen Loop, eingelesen wurde und jeweils die gleichen fünf Strings überkam.

In der Klasse des Adapters wurde durch den ViewHolder die richtigen Textviews ausgewählt, die Views kreiert und mit den Informationen, welche der Adapter bekam, gefüllt.

In der Mainactivity wurde dies alles in der onCreate() Funktion ausgeführt, was zur Folge hatte, das der ganze vorgang nur beim Öffnen der App ablieft, da die Funktion onCreate() nur einmal bei der ersten Ausführung der App aufgerufen wird. So konnte der Recyclerviewer erst nur einmalig mit Informationen versehen werde. Der CustomAdapter war am Anfang der App dafür zuständig die Daten, welche in einer einfache Klasse abgespeichert wurden, über den Constructor dem ViewHolder weiter zu geben, welcher dann diese Informationen an eine View im Recyclerviewer band. Im verlaufe der Zeit wurde der Adapter angepasst und erweitert. Dies hatte Simon auch sehr grossen Spass gemacht da er auch wirklich alles verstand, jedoch als die Database entstand war der alte CustomAdapter überflüssig und wurde ersetzt. Der neue CustomAdapter regelt seine Aufgaben jetzt ein wenig anderst. Zwar viel effizienter mit weniger Code aber nicht so Transparent. Der CustomAdapter wird wie der Recyclerviewer in jedem Fragment für den zugehörigen Folder neu Aufgerufen und überschreibt den CustomAdapter aus der Mainactivity.

3.2.7 Popup Window

Abbildung 4: Input Validation Wenn man den Add Email Button drückt, soll ein Popup Fenster erscheinen, wo man seine Anmeldedaten für ein neues Emailkonto hinzufügen kann. Da ein Emailserver aber auch von gewissen Standardeinstellungen wie beispielsweise vom standardmässigen IMAP Port 993 abweichen kann, wirden in diesem Fenster die Standardeinstellungne getestet, indem eine kurze Anfrage an den Server ausgeführt wird. Wenn die Anfrage erfolgreich ist, werden die Anmeldedaten in der App gespeichert. Wenn nicht, erscheint ein neues Fenster, wo man die genauren Emailserver Einstellungen testen kann.

Zusätzlich gibt es noch eine Input Validation. Dort wird gecheckt, ob die Eingabe korrekt ist, also ob der Nutzer eine gütlige Emailaddresse eingegeben hat oder dass er ein Eingabefeld nicht leer lässt. Das Feld mit der falschen Eingabe wird rot markiert und der Nutzer weiss somit, an welcher Stelle er seine Eingabe korrigieren muss.

3.2.8 Database

Da viele Daten gespeichert werden müssen, musste eine Möglichkeit her, wie diese möglichst schnell, und der Einfachheit halber mit einer gewissen Abstraktion, in einer sinnvollen Datenstruktur gespeichert werden können. Dazu taugte eine Datenbank für diesen Anwendungszweck und u.a. in Anbetracht der eingrenzenden Umständen, also die Deadline der Arbeitsabgabe, an. Noah hatte schon ein paar wenige Erfahrungen mit Datenbanken, doch da Simon diese Aufgabe übernehmen wollte, las er sich mithilfe eines Buches [Ric01] erfolgreich in die Thematik ein. Ein relational database management system ist ein Databasesystem in welchem die Informationen als tables gespeichert werden. Ein table besteht aus Reihen und Spalten. Eine Reihe repräsentiert jeweils ein Object der Database und eine Spalte repräsentiert ein Wert eines Attributes. Im Fall dieser App gibt es 9 Attribute und einen Objectkey.

Database Table

ObejctKey To  cc  bcc  from  date  subject textContent folder seen

01 Valentin null null Lennard 01.03.13 Schule Hallo Herr Konrad ...

Draft

true

Der Objektkey wird dafür genutzt das Objekt zu identifizieren und aufzurufen. Es können auch weitere dinge mit dem Objektkey gemacht werde. Je nach dem wie die Database eingelesen wird, kann am Objektkey festgestellt werden, zu welchem Zeitpunkt eine Objekt erstellt wurde. Bis auf seen und dem ObjektKey sind alle Attribute Strings. To ist das Attribute, welches angibt an wen die Email geschickt werden soll, From ist das genaue gegenstück dazu. Cc und bcc sind die Email-Adressen, welche die Emails auch bekommen. Der einzige unterschied ist, dass bei bcc diese Adressen nicht einsehbar sind und somit nicht bekannt ist wer diese Email auch liest. Date gibt das Datum an, an welchem die Email verschickt wurde. Subject ist ein Betreff für die Email und textContent ist der Text welcher in der Email verfasst wurde. Das Attribut Seen ist etwas spezieller. Es gibt an ob eine Nachricht von dem Nutzer Gelesen wurde oder nicht. Diese Info wird dann im Recyclerviewer genutzt um die Textart zu verändern in welcher die Email angezeigt wird. Diese Attribut muss verändert werden, wenn eine Email geöffnet wird.

Die Attribute To, from, date, folder und seen wurden im Databaseconstructor als @NonNull definiert, heisst sie müssen eingelesen werden und können nicht null sein. Das macht soweit Sinn, weil eine Email, bis auf seen, nicht ohne diese Angaben versendet werden können und ohne zu wissen in welchem Ordner die Email einzuordnen ist, kann die Email auch nicht richtig angezeigt werden.

Als letztes gibt es noch das Attribut folder, es gibt an, von welcher Art die Email ist. Es gibt in der App fünf Ordner. Sie heissen Draft, Sent Inbox, Spam und Archive. Die Database kann nach einzelnen Attributen ausgelesen werden. So können die Emails mit den richtigen folder Attributen, in den richtigen Ordnern angezeigt werden. Jeder Ordner hat sein eigenes Fragment, welches aufgerufen wird, wenn der Ordner ausgewählt wird. Wenn ein solches Fragment aufgerufen wird, wird auch die Database mit den richtigen Befehlen neu ausgelesen.

Für Android gibt es nicht viele Sprachen um eine Database zu erstellen. Die bekannteste ist SQLite .Jedoch ist SQLite nicht sehr simple und es kann sehr komplex werden, wenn die Database bis auf bytes genau Programmiert werden soll. Ebenfalls lag es nicht im Zeitplan eine weitere Programmiersprache zu lernen. Nach kurzer recherche stellte sich heraus, dass es eine Library gibt, welche den Umgang mit SQLite vereinfacht und diese sogar mehr Sicherheit bietet.

Abbildung 5: Room Struktur [Dev] Room ist eine Art Schicht über der SQLiteDatabase. Room besteht grundsätzlich aus drei Teilen. Die Database dient als Hauptzugriffspunkt für die gespeicherten Daten der App. Sie ist mit @Database markiert. Eine Entity repräsentiert einen table in der Database und die DAO Klasse beinhaltet die Methoden um auf die Database zu zu greifen. Sie kommuniziert mit SQ-Lite um de Zugriff auf die Daten zu ermöglichen [Gar]

3.2.8.1 MessageDao

In der DAO-Klasse können SQL statements verwendet werden. Um auf die Database zu zugreifen und nur Gewisse Objekte zu erfassen, hat Simon ein paar wenige SQL statements gebraucht. SQL ist zum Glück in diesem Fall sehr selbsterklärend, dennoch werden wir darauf eingehen.

    /* get Draft messages*/
    @Query("SELECT * FROM message_table WHERE folder LIKE 'Draft' ORDER BY date ASC")
    LiveData<List<Message>> getDraftMessages();

Querys sind anfragen an die Database nach Informationen. Sie können auf verschiedene tables zugreifen und Informationen abgleichen und auswählen. In einer DAO von Room werden die SQL-statements mit @Query markiert. SELECT heisst, dass etwas ausgewählt werden soll und mir * ist gemeint alles. Mit FROM wird nochmals angegeben von welchem table, in diesem Fall vom message table. Die Entity die wir weiter oben schon erklärt haben. Mit WHERE können Spalten der Entity ausgewählt werden. Hier wird die folder Spalte gewählt um mit LIKE ein Attribut zu bestimmen. So wird nun ein Attribut namens ’Draft’ gewählt. Mit ORDER By kann die Ausgabe noch sortiert werden. So wird die Ausgabe anhand der Spalte ’date’ nach dem ASC-code sortiert. [vha]

3.2.9 Repository/ViewModel

Abbildung 6: EmailViewModel and Re- pository [Dev] Mit der Database wurden auch ein Repository und ein Viewmodel mit Viewholder erstellt. Das Repository verwaltet die Datenquellen. Im Normalfall würde es Daten von einem Server verwalten und in die Database einlesen. Ebenfalls kann es auch Daten die der User direkt eingibt einlesen. Zwar nicht direkt von der Activity aber über ein Viewmodel können Daten in die Database eingelesen werden. Das Repository stellt dazu die Funktionen für das Viewmodel zur Verfügung. Da in diesem Falle keine anständige Java Library gefunden wurde, welche nicht uralt oder eine Dokumentation zur Verfügung hatte mussten die Daten vom Server mit einer Python Library eingelesen werden. Noah Programmierte dazu in Python mit einer Library ein Programm welches die Daten von eine Server herunterlädt und in die Database einliest. In diesem Falle das EmailViewModel, stellt Funktionen zur Verfügung, mit welchen auf die Database, über das Repository, zugegriffen werden kann. Ebenfalls gibt es LiveData zurück mit welcher die Mainactivity die observer Verknüpfungen erstellen kann. Mit dem ViewHolder in diesem Fall dem EmailViewHolder können Daten an View gebunden werde. In dem Fall wäre das der Recyclerviewer. So wird die Mainactivity informiert, wenn eine Änderung der Database vorgekommen ist. Im Fall dieser App wird zwar ein Recyclerviewer in der Mainactivity mit Observer und Adapter erstellt, jedoch wird dies nur gemacht um das gleiche für jedes Fragment zu machen, welche dann den Recyclerviewer und den observer aus der Mainactivity überschreiben. Die einzelnen Folder haben jeweils ein Fragment zugeordnet, in welchen der einzige unterschied ist, dass sie andere Attribute aus der Database abfragen um die den Folder entsprechenden Messages zu bekommen. An diesem Beispiel ist es vielleicht leichter zu verstehen. Dies ist die Funktion welche an einer Variable vom Typ EmailViewModel ausgeführt wird. In dem Fragment HomeFragment in der onCreateView Funktion, welcher immer ausgeführt wird wenn dieses Fragment aufgerufen wird.

       mEmailViewModel = new ViewModelProvider(this).get(EmailViewModel.class);
       mEmailViewModel.getInboxMessage().observe(getViewLifecycleOwner(), messages -> {
           /* Update the cached copy of the messages in the adapter*/
           adapter.submitList(messages);
       });

Die Funktion getInboxMessage() is im der Klasse EmailViewModel definiert und gibt LiveData¡List¡Message¿¿ zurück, was soviel ist wie eine Liste der Objekte in der Database, eingebettet in LiveData.

    public LiveData<List<Message>> getInboxMessage(){ return mInboxMessage;}

       private LiveData<List<Message>> mInboxMessage;
       public EmailViewModel(Application application) {
       super(application);
       mEmailRepository = new EmailRepository(application);
       mInboxMessage = mEmailRepository.getInboxMessages();

       }

       public LiveData<List<Message>> getInboxMessage(){ return mInboxMessage;}

    private LiveData<List<Message>> mInboxMessage;
    public EmailRepository(Application application) {
       EmailRoomDatabase db = EmailRoomDatabase.getDatabase(application);
       messageDao = db.messageDao();
       mInboxMessage = messageDao.getInboxMessages();

    }

       public LiveData<List<Message>> getInboxMessages() {
       return mInboxMessage;

    }

Im Cunstroctor von dem EmailViewModel wird der Variable mInboxMessage die Daten aus dem Repository übergeben welche diese wieder im Constructor von dem MessageDAO überkommt.

3.2.10 Draft Messages

Abbildung 7: App Structure [Dev] Der ganze Aufbau der in den Kapitel von vorhin erklärt wurde, hatte nur zwei Ziele. Einmal das einlesen von Emails von einem Server und das Einlesen von Emails über ein Fragment genannt messageCreate-Fragment. Diese Fragment interagiert mit einer Activity genannt NewDraftMessageActivity. Die Mainactivity startet beim Klicken auf einen Button das messageCreateFragment. Dieses liest die Daten ein welche der User in das Fragment schreibt und übergibt sie mit Hilfe der NewDraftMessageActivity direkt an die Message Klasse und somit in die Database.

Dies ist der grobe Aufbau um Messages anzuzeigen. Wenn etwas durch die NewDraftActivity verändert wird, wird der Observer informiert, welcher den CostumAdpater informiert und bis nach ganz unten die neuen Informationen ausliest.

3.3 Umsetzung

3.3.1 Bugs

Programmierfehler schleichen sich in jedem Softwareprojekt ab einer gewissen Komplexitätsstufe ein. Damit hatten auch die Entwickler diese Projektes zu kämpfen. Hier dazu ein kleines Beispiel: Als der RecyclerViewer das erste Mal eingebunden werden konnte, ohne dass die App nach dem Öffnen direkt abstürzt, war aber das Problem, dass am oberen Teil Inhalte abgeschnitten waren. Das konnte gelöst werden, indem diese Codezeile in der Datei app/src/main/res/layout/activity main.xml an der richtigen Stelle eingefügt wurde:

android:paddingTop="50dp"

3.3.2 Probleme / Hiccups

Probleme waren die unnötig vielen Layouts, welche entstanden bei unserer App. Vielleicht hätten diese minimiert werden können, wenn die Entwickler eine siginfikant höhere Erfahrung im Bereich der Android Entwicklung hätten, oder wenn die verschiedenen Inhalte beim Aufrufen weniger Layouts generieren würden, oder diese könnten besser wieder referenziert werden.

Mit gewissen Biobliotheken sind auch Probleme entstanden, dazu wird später in diesem Text noch das Problem mit den Email-Bibliotheken geschildert.

3.3.3 Kommunikation

Simon: Ich finde wir haben etwas wenig kommuniziert aber dafür lief es sehr gut. Ich war sogar eher froh das wir nicht ganz so viel Kommuniziert haben. Teilweise war ich auch deswegen gestresst aber ich konnte Noah so gut vertrauen, wenn ich ihm sagte wir sollten etwas bis zu einer gewissen Zeit schaffen hatte er es auch eingehalten oder Probleme mir gemeldet. Wir hatten gewisse Strukturen um die Kommunikation zu vereinfache. Wir

Noah Vogt & Simon Hammer  5 SELBSTREFLEXION

haben eine diary geschrieben, in welcher wir unseren Prozess dokumentiert haben. Und auf welchem auch grossteile der Dokumentation in der Maturarbeit basiert. Ebenfalls haben wir uns im Programm oder in unseren Texten Notizen überlassen um fragen an den anderen zu stellen oder Aufgaben zu geben. Teilweise haben wir uns auch jeden Montag zusammengesetzt und die Woche besprochen. Jetzt wo ich alles Aufzähle merke ich wir haben nicht ganz so wenig Kommuniziert aber es hat sich sehr danach angefühlt. Unter anderem, weil Noah selten erreichbar war. Dennoch Lief es sehr gut, auch weil wir uns das Programm grob aufgeteilt haben und sich alle Teile zusammenfügen, was auch einen gewissen touch der Linuxphilosophie in sich hat.

3.4 Testing

4 Resultate

4.1 Vergleich mit unseren ursprünglichen Zielen

4.2 Vergleich mit der Konkurrenz

4.3 Beschreibung der vorliegenden getesteten Funktionalitäten

4.4 Vor- und Nachteile unserer App

4.4.1 Pro

4.4.2 Kontra

5 Selbstreflexion

5.1 Was Gut Lief

Das Arbeiten mit Git als Version Control System verlief gut und half ihrer Meinnung nach enorm beim Arbeitsprozess und dessen Strukturierung. Mit der Syntax der verwendeten Programmier- und Markupsprachen Java, Python und XML konnte gut umgegangen werden, obwohl die beiden noch recht wenig Erfahrung mit Java hatten. Die Codestruktur fanden sie den Umständen entsprechen gut und sinnvoll.

5.2 Was Schlecht Lief

Dass es keine mit Gradle funktionierede, ausreichend dokumentierte und/oder nicht veraltete IMAP- und Emailbibliotheken für Java. Deshalb wichen wir auf die um Welten besser funktionierende Pythonbibliotheken imap und emaillib aus. Dazu mussten wir eine Library namens Chaquopy benutzen, um Python als Bytecode kompiliert in unsere Java App einbauen zu können. Das ist natürlich unschön, aber die Funktionalität wär halt die oberste Priorität.

Etwas das nicht direkt schlecht lief aber sehr viel Zeit brauchte ist, dass wenn ich (Simon) zum Beispiel eine Database für den Recyclerviewer gemacht habe, zwar nur eine Testversion, ich diese im späteren verlauf komplett überarbeiten durfte. Es war zwar nur eine Testversion aber dass diese so weit von einer professionelle Database entfernt war, war mit nicht klar. In so einer Situation war ich nicht nur bei der Database. Mit dem Recyclerviewer hatte ich solche Probleme sogar öfters. Oft hat zwar noch nicht viel funktioniert aber ich musste den Recyclerviewer öfters komplett umschreiben. Als ich die erste Version hatte, hatte ich eine sehr simple version einer Database und durch dies hat sich auch ein simpler Adapter entwickelt. Aber diesen konnte ich mit der Zeit sehr gut an de Recyclerviewer anpassen. Ich habe ihn auch sehr stark ausgebaut. Als ich jedoch eine vollstendige Version einer Database hatte, musste ich den Adapter so gut wie löschen. Solche Dinge haben den Arbeitsprozess sehr stark ausgebremst und die Arbeit begann mich zu nerven, da teilweise klar war, dass ich das was ich gerade mache sowieso nochmals überarbeiten muss.

Noah Vogt & Simon Hammer  6 DANKSAGUNG

5.3 Was Wir Gleich Machen Würden

Wenn wir diese in die Vergangenheit reisen könnten und die App von Neuem machen könnten, würden wir am Userdesign nichts ändern, und auch weiterhin mit Git als VCS arbeiten und für jedes noch nicht einsatzbereite Feature einen neuen Branch machen. Die Arbeitsweise an sich hat sich aus unserer Sicht bewährt und ist ein passabler Weg, kollaborativ an einem Softwareprojekt zu arbeiten.

5.4 Was Wir Anders Machen Würden

Code der in Java geschrieben wurde, kann nicht nativ auf einer Maschine laufen, sondern muss durch eine virtuelle Maschine, die Java Virtual Machine (JVM) während der Ausführung in nativen Code umgewandelt werden. Deshalb würde bei einem Rewrite wohl besser mehr Code in C oder C++ geschrieben werden, um die Geschwindigkeit und Portabilität zu erhöhen. Java komplett wegzulassen ist aber weder vorgesehen noch praktisch sinnvoll umsetzbar.

Uns ist öfters gesagt worden, dass das managen der Zeit sehr wichtig ist. Wir sind davon ausgegangen, dass wir dies auch gut eingeplant haben. Dem war leider nicht so und wir würden uns mehr gedankten machen beim Planen wie auch, wie lange wir an einem Problem arbeiten bevor wir das Feature entfernen, als das wir sehr lange daran arbeiten.

5.5 abschliessende persönliche Schlussfolgerung

Wir haben das Gefühl, einen guten ersten Einblick in die native Android Programmierung mit Java und Python bekommen zu haben. Wir haben uns vertraut gemacht mit den Vorzügen aber auch Nachteilen dieser Art von Programmierung und der Plattform Android.

Wir sind zwar etwas enttäuscht, dass wir nicht alle geplanten Ziele erreicht haben, doch wir haben noch genug Motivation die App in den nächsten paar Wochen und Monaten fertigzustellen. Denn die Arbeit hat uns insgesamt doch gefallen, trotz einigen Motivationstiefs, sodass wir auch gerne unseren Freunden und Familie von ihr erzählt haben.

Was uns auch noch sehr gefallen hat ist das Arbeiten mit dem Version Control System Git und der Plattfrom Github, denn so konnte man gut den Fortschritt sehen und tracken, schliesslich machte das kollaborative Arbeiten an einem Projekt dieser Grösse besonderns Sinn und konnte gut Nutzen machen von der Funktionalität dieses Systems.

6 Danksagung

Wir (Simon und Noah) möchten uns bedanken bei unserer Betreuungslehrperson Dr. Viktor Yakonthov, und unserem Koreferenten D. Bühler bedanken, dass sie uns die Arbeit erlaubt haben durchzuführen und ihre Bereitschaft, zu Helfen bei allfälligen Fragen.Free Software FoundationFree Software

Noah Vogt & Simon Hammer  LITERATUR

Literatur

[Sal94] P.H. Salus. A Quarter Century of UNIX. Addison-Wesley UNIX and Open Systems Series. Addison-Wesley Publishing Company, 1994, S. 66. isbn: 9780201547771.

[Ric01] G. Riccardi. Principles of Database Systems with Internet and Java Applications. Addison-Wesley, 2001. isbn: 9780201612479.

[SGF02] R. Stallman, J. Gay und F.S. Foundation. Free Software, Free Society: Selected Essays of Richard M. Stallman. Free Software Foundation, 2002. isbn: 9781882114986.

[Sta07] Richard Stallman. The GNU General Public License v3.0 - GNU Project - Free Software Founda-

         tion. https://www.gnu.org/licenses/gpl-3.0.en.html. (Accessed on 09/17/2021). Juni

2007.

[DP09] T. Dalzell und E. Partridge. The Routledge Dictionary of Modern American Slang and Unconventional English. Routledge, 2009, S. 595. isbn: 9780415371827.

[Kum11] C.A. Kumar. Welcome to the ’free’ World: A Free Software Initiative. Indian Universities Press, 2011, S. 28–29.

[Ano20] Anonymous. /t/ - Open Source Licenses. https://8chan.moe/t/res/865.html. (Accessed on 09/19/2021). Aug. 2020.

[BGV20] S. Bhattacharya, K. Gopinath und D. Voigt. Resource Proportional Software Design for Emerging Systems. CRC Press, 2020. isbn: 9781351682336.

[Smi21] Luke Smith. Why I Use the GPL and Not Cuck Licenses – Luke Smith. https://lukesmith.xyz/articles/why-i-use-the-gpl-and-not-cuck-licenses.

(Accessed on 09/19/2021). Apr. 2021.

[suc21] suckless.org. software that sucks less — suckless.org software that sucks less. https://suckless.org/philosophy/.

(Accessed on 09/16/2021). 2021.

[Ano] Anonoymous. LayoutManager — Android — myMusing. https://mymusing.co/layoutmanager-android/.

Edited by Simon.

[Dev]  Android Developers. Android Room with a View - Java. https://developer.android.com/codelabs/android-room-with-a-view#15.

Edited by Simon.

[Gar] Sagar Garg. Room Persistence Library - DZone Database. https://dzone.com/articles/room-persistence-library.

(Accessed on 09/19/2021).

[vha]  vhaecky. Android Room with a View - Java. https://developer.android.com/codelabs/android-room-with-a-view#0.

(Accessed on 09/19/2021).