2021-02-09 Achievements und Technical Error Overlay

Diese Woche ging es wieder Schlag auf Schlag weiter und wir waren mit dem was wir erreicht haben sehr zufrieden.

In unserem Backlog wird die Liste der Bugs nach und nach etwas größer. Deshalb haben wir uns vorgenommen jede Woche mindestens einen Bug zu bearbeiten und möglichst zu fixen.
Wir haben uns den folgenden Bug vorgenommen: App wird mit Fehler beendet, wenn der Webserver nicht erreichbar ist.
Easy oder? Uns war klar, dass es in diesem Umfeld (Zugriff auf den Webserver) mehr als nur diesen einen Fehler gibt. Wir haben uns also nicht auf die Lösung des Bugs beschränkt, sondern gleich ein komplettes TechnicalErrorOverlay eingeführt.
Wir können nun an einer beliebigen Stelle unserer App einen technischen Fehler auslösen. Für uns sind das die Art von Fehler, auf die wir in der App entweder keinen Einfluss haben (z.B. Webserver oder IdProvider nicht erreichbar) oder Fehler, die niemals auftreten dürfen. Tritt ein Fehler dieser Kategorie auf, wird bei der nächsten Möglichkeit im UI ein Overlay-Screen angezeigt und der Anwender kann mit dem im Hintergrund liegenden Screen nicht mehr interagieren. Aber er kann den Screen refreshen. Funktioniert der Refresh kann mit der App normal weitergearbeitet werden. Tritt erneut ein Fehler auf, wird der Technical Error Overlay wieder angezeigt.
Neben einer Meldungsausgabe für den Anwender geben wir auch den technischen Fehler selbst aus. Das kann bspw. ein Exception-Text sein, mit dem wir dem Fehler schneller auf die Schliche kommen können. Später wollen wir die technische Meldung ausblenden, da der Endanwender damit nichts anfangen kann.
Letztendlich hat uns diese kleine Umsetzung 1 1/2 Tage gekostet :D. Egal, denn wir profitieren davon in jedem bestehenden, jedem neuen Fragment und können nun an beliebigen Stellen technische Fehler auslösen.

Ein zweites großes Thema waren Achievements. Für uns sind Achievements ein wichtiger Bestandteil der App, um den Benutzer zu motivieren und ihn zu belohnen. In dem Sprint haben wir uns vorrangig auf das Layout beschränkt. Es gibt eine Achievement-Liste, die derzeit alle vom angemeldeten Benutzer erreichten Achievements anzeigen soll.
Pro Achievement gibt es eine Kachel mit einem Bild, Titel, Fortschritt und Datum. An dem UI haben wir besonders lang gesessen und bemüht mit einem Wasserzeichen im Hintergrund zu arbeiten und die Kacheln transparent darzustellen. Die Farben haben sicherlich noch nicht ihren endgültigen Stand, aber das Layout, der Aufbau an sich, gefällt uns echt gut. Und so sehen sie derzeit aus:

2021-02-02 Springboard

Ab jetzt ist es eine App. In diesem Sprint haben wir das Springboard implementiert. Das Springboard ist unser Dashboard, unsere Startansicht. Von hier kann der Benutzer in alle Teile der Anwendung navigieren.

Die Implementierung selbst war gar nicht so kompliziert, denn mittlerweile haben wir ausreichend Wissen in allen Bereichen. Wir wissen, wie wir einen Endpunkt im Backend hinzufügen können. Unser JWT (Json-Web-Token) aus Keycloak unserem IdProvider wird automatisch jedem REST-Request hinzugefügt und wir müssen uns hier um nichts mehr kümmern, und unser UI-Framework hilft uns bereits schon sehr, neue Features schnell und auf einem standardisierten Weg hinzuzufügen.

Von nun an kann der Benutzer in eine Liste abspringen, die lediglich Teams anzeigt, denen er zugeordnet ist. Im Dashboard gibt es außerdem Live Informationen, die man zu einer Kachel im Dashboard anzeigen kann. Für die Kachel „My teams“ ist es bspw. die Anzahl der Teams, denen man zugeordnet ist.
Außerdem kann der Benutzer neue Teams hinzufügen – denen er automatisch beim Anlegen hinzufügt wird. Das ganze Dashboard aktualisiert sich automatisch.
Last but not least haben wir das Userprofil umgezogen. Auch dieses kann vom Dashboard aufgerufen werden. Und so sieht es aus:

Dashboard Stand 02.02.2021

Was haben wir noch gemacht? Für die App haben wir noch kleinere Bugs gefixt und Zeit investiert, um Coding aufzuräumen. Unsere ids der UI-Komponenten haben wir harmonisiert und alle REST-Aufrufe laufen nun nur noch ausschließlich über unsere Service-Klassen. Damit haben wir eine klare Trennung zwischen REST-Aufrufen, Model und UI-Implementierungen, die wir vorher noch nicht zu 100% eingehalten haben.

Ein paar organisatorische Dinge gab es auch noch zu erledigen. Bisher haben wir unseren Blog nie gesichert. Jetzt gibt es ein wöchentliches Backup. Mittlerweile wäre es sehr schade, wenn wir die Arbeit am Blog verlieren würden. Gerade die Achievements, die Verena als Timeline hinzufügt hatte und regelmäßig pflegt, finden wir beide mega cool. Um die wäre es besonders schade.

Insgesamt waren wir echt fleißig und uns graut es schon vor dem morgigen ABAP-Müll. Wäre toll, wenn wir stattdessen hier weiter machen könnten.

2021-26-01 Refactorio

Eine Woche des kompletten Umkrempelns geht zu Ende und unsere vier Hände gehen zur Siegerpose in die Luft: das ViewState-Konzept ist gerefactored! Lange haben wir mit wachsend skeptischem Blick der Code-Duplizierung zugesehen, wenn wir ein neues Feature angelegt haben. Dafür musste neben einem Fragment und ViewModel mindestens ein ViewStateUpdater, eine zugehörige Factory, Events und zugehörige Results und Methoden auf dem ViewModel, die lediglich Parameter durchgeschleift haben, angelegt werden. Das Coding dafür haben wir mangels einer besseren Lösung von Klasse zu Klasse kopiert und bei jedem Aufruf eines unserer Events hat mindestens einer von uns geflucht, dass man selbst diesen Aufruf, der doch eigentlich ganz einfach zu handhaben sein sollte, kopieren musste. Wir haben es lange aufgeschoben, weil wir genug Beispiele sammeln wollten, um eine für uns perfekte, allumfassende Lösung zu finden. Es hat zwei Tage gedauert, aber jetzt ist alles aufgeräumt und wir sind mit der Lösung mehr als zufrieden 🙂

Ein Event, meistens durchs UI getriggert, hatte bis jetzt immer ein zugehöriges Result, welches Werte gehalten hat, um den ViewState zu manipulieren. Die ViewStateUpdater haben sich dann um das Kopieren und Updaten des ViewStates gekümmert. Obwohl Events und Results beide im StateFlow untergebracht waren, fehlte trotzdem etwas der Zusammenhang. Das Einzige, was sie gemeinsam hatten war der Name. Jetzt haben wir alles in einer „Action“ verpackt. Hier kann in der Start-Methode bei länger laufenden Calls ein Flow zurück zu geben oder Daten, die wir im UI anzeigen wollen, gleich gecached werden, um damit den ViewState anzupassen. In einer weiteren Finish-Methode kopieren wir den ViewState und setzen die Properties, so wie sie im UI angezeigt werden sollen. Wir haben die Möglichkeit, auf Exceptions zu reagieren, eine Action aus einer Action heraus zu triggern und zu anderen Fragments zu navigieren. Die Funktionalität für jede Aktion eines Features ist jetzt an einer zentralen Stelle und unser Framework kümmert sich um die Abarbeitung. Man muss lediglich wissen, dass zum Ausführen einer Action „callAction“ aufgerufen werden muss und sonst nichts. Sweet.

Zwischen drinnen haben wir wie immer noch ein paar Dinge ins Framework umgezogen, wie z.B. ein initiales Update des ViewStates, damit die UI diesen nicht zu Beginn selbst triggern muss und wir haben uns mit Reflection in Kotlin beschäftigt, um die Copy-Methode unserer Data classes auf Instanzen aufrufen zu können, von deren Typ uns nur das Interface zur Verfügung stand. Und sicher noch eine Menge kleiner Sachen, die man gar nicht mehr alle aufzählen kann, aber die uns das Leben Woche für Woche einfacher machen und uns erlauben, Fahrt aufzunehmen. „Die Züge sind erforscht: Tut tut, wir kommen!“

2021-01-19 Happy New Year

Wir waren zum Jahreswechsel etwas nachlässig mit unseren Blogeinträgen und bevor es noch schwieriger wird alles zusammen zu bekommen was wir in den letzten Wochen geschafft haben, hier ein Schnelldurchlauf. An der UI hat sich geringfügig etwas verändert, aber hauptsächlich haben wir uns mit dem Aufbau des UI-Frameworks und Refactoring beschäftigt.

Wir haben ein BaseTabStripFragment eingeführt, mit dessen Hilfe wir einen Tab-Strip anzeigen können und welches als Wrapper dient und das sich z.B. um die Anzeige des Titels in der Toolbar kümmert, damit dies nicht auf jedem Tab-Fragment einzeln implementiert werden muss. Den Tab-Strip haben wir implementiert, um die Details zu einem Team in Overview, Achievements und Member zu trennen. Derzeit sind die einzelnen Tabs noch so gut wie leer, aber sobald wir hier etwas Content haben, werden wir die neue UI präsentieren.

Auch unser Backend haben wir um User und Team-Member erweitert und sichergestellt, dass ein User, der ein Team anlegt, diesem auch als Member zugewiesen wird. Außerdem haben wir bei der Gelegenheit etwas Zeit in das Error Handling gesteckt. Wir geben sprechende Nachrichten zurück und trennen unsere Request-Result mittels Codes nach z.B. 404-Bad Request-Fehlern, wenn ein Methodenaufruf unerwartet schief geht und 405-Method not allowed-Fehler für z.B. Fehlern bei der Validierung. Der Aufbau unseres Results hat sich durch das Einführen eines ResultBuilders deutlich vereinfacht. Durch die Codes können wir uns jetzt auch App-seitig je nach Fehler an einer zentralen Stelle im ServiceExecutor darum kümmern und bekommen bei App-Abbrüchen nun viel sprechendere Nachrichten. Für uns ein absolutes Plus.

Diese Woche haben wir unsere ServiceExecutor-Calls in extra Services gewrappt, um die Aufrufe einfacher zu machen. In diesem Zuge haben wir gleich eine saubere Trennung zwischen den DTOs und DOs vorgenommen. Die DTOs werden nun ausschließlich für die Webschnittstelle verwendet  und haben jeweils eine to<Model-Klasse>-Methode, um die Werte in unsere DOs zu mappen und mit diesen weiterzuarbeiten.

Da wir mit Dagger bisher nicht weitergekommen sind, wir aber gerne in Zukunft unsere Services zu Testzwecken mocken möchten, haben wir einen Service Provider eingeführt.

Wir hatten auch eine UI zum Joinen eines Teams angelegt und dachten heute, wir könnten beim Klick auf den Hinzufügen-Button „mal eben“ eine Snackbar anzeigen. Die Diskussionen und Implementierung sind wie immer etwas „ausgeartet“ 😛 Dafür handelt unser Framework nun so mal wieder so gut wie alles und wir können Snackbars mittels ViewState einblenden und sie werden automatisch wieder ausgeblendet. Moment..Ausblenden macht die Snackbar doch selbst? Aber sie gibt uns darüber keine Rückmeldung. Das bedeutet, dass wir unseren ViewState nicht aktualisieren können und somit die UI und der ViewState auseinander laufen würden. Deshalb haben wir uns dafür entschieden, uns selbst um die Anzeige der Snackbar zu kümmern, um z.B. beim Rotieren genau den gleichen Zustand wiederherzustellen.

2020-12-15 Umgestaltung und Änderbarkeit des User Profiles

Was haben wir die letzten beiden Tage gemacht? Bereits in der letzten Woche haben wir mit dem Userprofil begonnen. Mit dem Layout waren wir noch nicht zufrieden und geändert werden konnte es bisher auch nicht. Darum haben wir uns nun gekümmert. Nach dem Update sieht es nun wie folgt aus:

Im Kopf werden der Username und die E-Mail Adresse angezeigt, die nicht geändert werden können.
Im unteren Bereich die änderbaren Attribute. Aktuell nur der Vor- und Nachname. Über einen Änderungsbutton öffnet sich ein Alert Dialog, um den Wert zu ändern. Für eine gute Wiederverwendung haben wir den Dialog gekapselt.
Außerdem haben wir eine Möglichkeit geschaffen, um das Profilbild zu aktualisieren.

Last but not least haben unsere UI-seitigen Implementierungen ein Lifting bekommen:
– So ist unser „ViewState“ in den Frameworkbereich eingezogen. Dadurch haben wir einiges an doppeltem Coding gespart.
– Wir handeln das Refreshen per SwipeRefreshLayout. Dafür muss das Layout lediglich ein SwipeRefreshLayout-Element bekommen. Beim Erzeugen eines Fragments wird auf diesen Elementyp geprüft. Ist dieser vorhanden, registrieren wir uns auf das Refresh-Event und updaten automatisch unseren ViewState, indem wir ein Standardattribut „isLoading“ aktivieren.

Das wars die Tage.

2020-12-08 Einführung Profiluser, Vervollständigung Teamliste

Am letzten Montag haben wir mit etwas Feinschliff an der Teamliste begonnen. Verena hatte im letzten Sprint bereits mit der Suche in der Teamliste angefangen. Die Tage haben wir die funktionale Implementierung abgeschlossen und einen Massentest durchgeführt.
Die Teams werden angezeigt und können problemlos gefiltert werden. Unser Massentest bestand aus 10.000 Teams, die wir im Backend erzeugt haben. Auch das Auslesen der 10.000 Einträge aus dem Backend aus der App ging unerwartet schnell (wohlwissend, dass der Webserver lokal läuft).
Momentan laden wir noch alle Teams. Später werden wir sicherlich auf ein Paging umstellen, um nicht alle Teams mit einmal laden zu müssen. Das Backend hatten wir auch bereits dafür vorbereitet.

Nachdem wir unsere Teamliste so langsam abgeschlossen hatten, wollten wir uns besonders am Dienstag um die Anzeige der Fragments für User kümmern. Letztendlich ging es vorrangig um das Handling des Profilusers: Auslesen und Anzeigen des Profils zum eingeloggten User.

Auf den ersten Blick müssen User-Informationen aus dem Backend ausgelesen und in der Android App angezeigt werden.
Auf dem zweiten Blick steckt etwas mehr dahinter. Wie kommen die User ins Backend? Außerdem existieren sie doch bereits im Identity Provider.
D.h. wir haben unser Backend weiter aufgebohrt. Es ist nun in der Lage mit dem Identity Provider zu kommunizieren. Auf einer Seite eine unerwünschte Abhängigkeit, aber so konnten wir problemlos alle aktuellen User im Keycloak-System auslesen.
Sobald der Webserver gestartet wird, liest er nun automatisch die User aus dem Keycloak-System und erstellt User-Objekte. Allgemeine Informationen wie Username, Vorname, Nachname und E-Mail Adresse werden ebenfalls ausgelesen und dem Backend-User hinzugefügt.
Sobald nun ein App-Benutzer einen Web-Request zum Backend absetzt, können wir die UUID aus dem übermittelten Token einem User aus dem Backend zuordnen, der aus den Userdaten des Keycloak-Systems erzeugt wurde.
Langfristig müssen wir uns noch Gedanken über eine generelle Synchronisierung machen. Derzeit haben wir Test-User, die wir „immer“ verwenden. Was aber, wenn sich ein neuer User registriert? In diesem Fall soll ebenfalls ein User im Backend erzeugt werden. Sicherlich gibt es in diesem Umfeld noch viele andere Testfälle, die wir umsetzen müssen.

Kurzerhand haben wir noch die Anzeige des Userprofiles komplett implementiert. D.h. ein Benutzer loggt sich ein, er hat nun die Möglichkeit sein Profil mit den Daten aus dem Backend, die aus Keycloak ausgelesen wurden anzuzeigen und der Benutzer kann sich ausloggen.
Wir sind mega stolz, was wir diese Woche geschafft haben.

Hier ein Bild zur Anzeige des User Profiles.

2020-12-01 Licht am Ende des Bilder-Tunnels

Obwohl wir diese Woche nicht mit voller Kapazität an unserem Projekt gearbeitet haben, sind trotzdem ein paar sehenswerte Dinge hinzugekommen und der Übersichtsscreen für die Teams und der zum Anlegen eines Teams sind fast fertig. Zum einen haben wir noch die letzten Bugs für unseren Upload von Dateien ausgemerzt. Bisher hatten wir das Problem, dass wir seit dem Umbau zum Anlegen eines Teams und gleichzeitigem Hochladen des Profilbildes kein Team mehr ohne Bild anlegen konnten. Nun haben wir auf Retrofitseite und Webservice-seitig den Image-Parameter auf optional bzw. in Spring auf „required = false“ gesetzt.

Beim Bildupload sind wir serverseitig auf ein 1MB-Limit gestoßen, weshalb die App gecrashed ist, sobald man versucht hat, ein größeres Bild hochzuladen. Da dies ohnehin für Bilder zu groß ist, verkleinern wir die Bilder nun vor dem Upload, wozu wir uns einen ImageResizer angelegt haben.

Außerdem können in der Teamliste die Einträge jetzt auch durch ein Swipen nach unten gerefreshed werden. Hierzu war lediglich das Platzieren der RecyclerView, die unsere Teams hält, innerhalb eines SwipeRefreshLayouts nötig, welches Android bereitstellt. Dadurch bekommt wir das Lade-Icon geschenkt und müssen uns lediglich auf den Swipe registrieren, um uns um den Refresh zu kümmern. Hier haben wir auch zum ersten Mal das Loading im LCE-Konzept (Loading/Content/Error) genutzt und es war fürs erste sehr gut verwendbar.

Der Pfad zum App-Cache ist derzeit hardgecoded und soweit wir gesehen haben, kann man nur über den Android-Context an den Pfad kommen. Dieser steht uns aber in unseren Repositories nicht zur Verfügung und Dagger ist uns nach wie vor ein kleines Rätsel. Deshalb hat sich Peter dazu entschlossen, einen ServiceProvider einzuführen und wir kämpfen hier noch etwas mit der generischen Implementierung. Aber wir wollen ja für nächste Woche auch noch etwas übrig lassen 😉

2020-11-24 The show must go on

Noch ein Monat bis Weihnachten. Unser Vorhaben Ende Oktober eine grob fertige Version unserer App umgesetzt zu haben, haben wir zwar nicht erfüllt, trotzdem sind wir die letzten beiden Tage unserem Ziel wieder etwas näher gekommen.

Die letzten beiden Tage haben wir uns wieder komplett der Anzeige von Bildern gewidmet. Wieder ein Thema, dessen Bearbeitung eine gewisse Zeit und Aufmerksamkeit benötigt. Jedem Team soll ein Bild zugeordnet werden können, das es repräsentiert. Wird auf das Team geklickt, werden die Details inklusives des Bildes angezeigt. Einen Teil davon hatten wir auch bereits in den letzten beiden Sprints umgesetzt.

Für die Umsetzung hatten wir auch jede Menge Ideen. Vor allem wollten wir die Anzahl der Requests zum Backend gering halten und die Bilder aller Teams in einem Rutsch beschaffen. Außerdem sollten Bilder clientseitig gecacht werden, um sie nicht nach jedem Restart der Anwendung oder Refresh der Team-Liste neu auszulesen. Wie gewohnt haben wir es nicht auf Anhieb hinbekommen, sondern hatte ausreichend Probleme mit mehr oder weniger allen beteiligten Komponenten. Ans Spring Boot Backend wollten wir einen Request mit allen Team-Ids schicken, für die das Bild zurückgegeben werden muss. Retrofit sollte alle Images entgegen nehmen. Jedes angezeigte Bild in der App sollte sich refreshen, sobald wir das Ergebnis vom Backend zurückbekommen haben. In Kotlin gibt es dafür das coole Flow-Konzept. Mit der Umsetzung hat es allerdings gehapert. Letztendlich hat es uns fast den gesamten ersten Tag gekostet.

Am zweiten Tag haben wir einen anderen Weg probiert. Das Framework Glide kann zum Laden von Bildern verwendet werden. Verena kannte das Framework bereits und letztendlich hat es sich als großen Mehrwert rausgestellt. Glide kann einen Platzhalter für ein Bild anzeigen, Glide kann Bilder von einer beliebigen Datenquelle – unter Berücksichtigung eines JSON Web Tokens – auslesen, Glide kann ein beliebiges Image im Falle eines Fehler anzeigen, Glide kann sich um das Cachen von Bilder kümmern. Kurz Glide bietet alles was wir benötigen. Die Änderungen vom Montag haben wir wieder ausgebaut und auf Glide umgestellt.

Zu guter Letzt hat Verena unseren ImagePicker auf unser App-Theme umgestellt und einen blöden Bug beim Anlegen eines Teams gefixt.

War mega, was wir erreicht haben.

2020-11-17 Ein Bild – ein Team

Diese Woche haben wir uns weiter mit der Übertragung von Bildern beschäftigt. Letzte Woche hatten wir die Funktionalität implementiert, um ein Bild einzeln zu übertragen und z.B. einer Entity anhand einer ID dieses Bild zuzuordnen. Um ein Team anlegen zu können müssen allerdings die Teaminfos und das Bild gleichzeitig übertragen werden. Mit Postman hatten wir relativ schnell den Endpunkt konfiguriert, hatten dann allerdings etwas länger damit zu kämpfen, die Informationen über Retrofit mitzugeben. Wir erstellen jetzt eine JSON-Datei für die Teaminfos und übergeben beide Dateien, Bild und Json-Datei als Multipart-Parts. Seltsamerweise gibt es in Postman nur die Möglichkeit, per Radio-Button als Content-Type „multipart/form-data“ für den gesamten Call mitzugeben, für unseren Retrofit-Call musste allerdings für die JSON-Datei der Typ „application/json“ und das Bild als form-data definiert werden. Das war wieder ein bisschen Gefrickel mit RequestParam/RequestPart 😀 Deshalb ist das diese Woche auch schon alles von uns, aber wie immer haben wir eine Lösung implementiert, die für jedes Bild mit Entity funktioniert. Nächste Woche werden wir dann auf Android-Seite nochmal etwas refactorn, damit auch hier der Aufruf in einer API gewrappt ist und wir uns mit dieser Thematik beim nächsten Call dieser Art nicht nochmal beschäftigen müssen.

2020-11-10 Die ersten Bilder

Die letzten beide Tagen waren wieder sehr produktiv. Es klingt einfach, für uns war es aber viel Arbeit: wir können jetzt die ersten Bilder in der App anzeigen. Speziell geht es um das „Profilbild“ eines Teams. Ein Bild, das ein Team repräsentiert. Ein Bild, das in der App erstellt und im Backend gespeichert und aus dem Backend geladen und in der App wieder angezeigt werden kann.

Für den Sprint hatten wir uns an sich viel mehr vorgenommen. Die Anzeige eines Bildes zum Team war nur einer von vielen Punkten auf der Todo-Liste. Wir wollten mit dem Benutzerprofil beginnen. Das Profil pflegen, Benutzer einer Gruppe hinzufügen etc. – aber Teufel und Detail!

Am Montag haben wir viel Arbeit ins Backend gesteckt. Wir haben generell die Möglichkeit geschaffen Bilder von einem Client hochzuladen und zu speichern und vom Server zu laden. Um das Feature haben wir eine kleine Api gestrickt, um das Hoch- und Runterladen zu verallgemeinern. Brauchen wir zukünftig ein Bild, das eine bestimmte Entität repräsentieren soll, muss diese Entität nur noch ein Interface implementieren und zwei Endpunkte für das Hoch- und Runterladen bereitstellen, die zwei Methoden der Api aufrufen müssen.
Automatisch werden die Dateien zur Entität in einem separaten Order, dessen Name standardisiert über alle Entitäten hinweg ist, abgelegt. Natürlich weiterhin unter der Voraussetzung, das ein gültiger Identity Provider Token übermittelt wurde.

Den restlichen ersten Tag und den zweiten haben wir mit Entwicklungen in der App verbracht.
Wir brauchten eine Möglichkeit, um Bilder über die Kamera aufzunehmen und sie in der App anzuzeigen. Verena hatte nach kurzer Recherche einen ImagePicker gefunden, den wir dazu verwendeten.
Viel Arbeit hat das Up- und Downloaden des gewählten Bildes auf den Webserver gemacht. Vor allem hatten wir Probleme damit den Call über Retrofit richtig abzusetzen. Nachdem wir das geschafft hatten, gab es nicht mehr viel Zeit und wir haben uns um unseren Teamdetailscreen gekümmert. Yay, wenn wir jetzt ein Team anzeigen, wird das zuvor zugeordnete Bild geladen und angezeigt.

Das war es diese Woche. Viele Ideen haben wir noch für das Refactoring zur Vereinfachung unserer App-Apis. Außerdem wird das Laden der Bilder auf Dauer viel Datenvolumen schlucken. Deshalb werden wir einen App-Cache vorsehen. Dieser soll sich immer dann aktualisieren, wenn es eine neuere Version des Bildes auf dem Server gibt.