From db9248778243fe590886520ff5007f43c210f19f Mon Sep 17 00:00:00 2001 From: Oschly Date: Thu, 14 May 2026 20:22:03 +0200 Subject: [PATCH] Most of the data model thesis part --- Thesis/Chapters/3. Implementation.typ | 66 +++++++++++++++++++++++++++ Thesis/main.pdf | 4 +- 2 files changed, 68 insertions(+), 2 deletions(-) diff --git a/Thesis/Chapters/3. Implementation.typ b/Thesis/Chapters/3. Implementation.typ index 56f6d7f..09eb8cf 100644 --- a/Thesis/Chapters/3. Implementation.typ +++ b/Thesis/Chapters/3. Implementation.typ @@ -1,9 +1,75 @@ +#import "../style.typ" #set heading(numbering: "1.1") = Implementacja == Projekt architektury systemu +Przygotowana implementacja bazuje na architekturze Model-View. Jest to podejście, gdzie cała logika biznesowa jest zawarta w modelach, które bezpośrednio są przekazywane do warstwy prezentacji (View). Na tej warstwie jest wykonywane odpowiednie formatowanie danych, gdzie też brane pod uwagę są preferencje zapisu i językowe użytkownika. Model-View to uproszczony wariant popularnej w aplikacjach mobilnych architektury Model-View-ViewModel (MVVM), gdzie ViewModel jest warstwą zajmującą się przekształcaniem modelów biznesowych na gotowe do prezentacji obiekty. Warstwa View wtedy zajmuje się przede wszystkim definiowaniem struktury interfejsu użytkownika oraz logiką związaną z dostępnością (wsparcie dla funkcjonalności czytników ekranów, skalowaniem interfejsu). Przygotowana implementacja nie zawiera złożonej logiki prezentacji ani rozbudowanego graficznego interfejsu użytkownika, więc w celu uproszczenia kodu zdecydowałem się na porzucenie użycia warstwy ViewModelu. + +Warstwa prezentacji aplikacji opisująca początkowy interfejs użytkownika jest zaimplementowana w `AllNotesScreen`. Ekran jest widoczny dla użytkownika, gdy ustawił swoją nazwę użytkownika w sieci peer-to-peer. Składa się z listy podzielonej na dwie sekcje - notatek których użytkownik jest autorem, oraz notatek do których użytkownik został zaproszony. Nad listą znajduje się przycisk stworzenia nowej notatki. Naciśnięcie na którąkolwiek z istniejących notatek prowadzi do otwarcia jej zawartości. W zależności od tego, czy użytkownik jest właścicielem danej notatki czy współtwórcą, interfejsem do edycji tej notatki są odpowiednio obiekty `NoteEditorScreen` oraz `SharedNoteEditor`. Z ekranu `NoteEditorScreen` możemy przejść do `ManageMembersScreen`, który jest listą użytkowników zaproszonych i możliwych do zaproszenia do edytowania aktualnej notatki. + == Model danych +Podstawowym obiektem reprezentującym notatkę w systemie plików jest `Note`. Składa się on z URL (Universal Resource Locator), czyli ścieżki prowadzącej do pełnej zawartości notatki użytkownika, która jest przechowywana w pliku tekstowym o rozszerzeniu `txt`. Dodatkowo przechowujemy w tym obiekcie jeszcze `name`, które pełni funkcję ułatwionego dostępu do przyjaznej nazwy, jednocześnie będąc nazwą pliku w lokalnym systemie plików oraz przyjazną nazwą prezentowaną w liście notatek do których użytkownik został zaproszony. Obiekt implementuje protokół `Identifiable`, który gwarantuje możliwość identyfikacji obiektu w zbiorze zawierającym wiele jego instancji, np. w tablicy. Ta cecha jest wymagana i wykorzystywana przez SwiftUI, by móc rozróżniać rodzaje zmian na komponentach interfejsów graficznych zawierających wiele kopii takiego obiektu, np. `List` lub `ForEach`. Umożliwia to dokonanie decyzji co do sposobu animacji zmian na ekranie użytkownika, ponieważ framework będzie mógł rozróżnić usunięcie i wstawienie nowego obiektu, od zmiany parametrów tej samej instancji. + +```swift +struct Note: Identifiable { + var id: URL { path } + + let name: String + let path: URL +} +``` + +`NoteMessage` to obiekt zawierający zawartość notatki, którą wysyłamy do użytkowników, którzy przyjęli zaproszenie do edycji notatki. Znajdziemy w niej pola `SenderID`, które jest identyfikatorem właściciela notatki oraz `content`, czyli właściwą zawartość notatki. Jest ona również używana do wysyłania każdej aktualizacji do wszystkich użytkowników. Obiekt implementuje protokół `Codable`, który jest uniwersalnym interfejsem kodowania danych. Daje to nam wbudowane wsparcie kodowowania do formatów JSON i XML. Mamy możliwość również pisania własnych koderów, które umożliwią zamianę obiektów implementujących `Codable` do wybranych przez nas, innych formatów danych. + +```swift +struct NoteMessage: Codable { + let senderID: String + let content: String +} +``` + +Do reprezentacji zaproszeń stworzyłem obiekt `NoteInvitation`. Przechowuje on informacje potrzebne do obsługi całego procesu zaproszeń między użytkownikami systemu. Składa się z `invitatorID`, który jest wyspecjalizowanym obiektem frameworku `MultipeerConnectivity` i umożliwia identyfikację użytkownika w czasie komunikacji peer to peer. `note` to obiekt reprezentujący notatkę, którą otrzymujemy w zaproszeniu. Składa się on z tytułu i treści, które były aktualne w momencie zapraszania użytkownika. Ostatnim i jednocześnie prywatnym parametrem jest `invitationHandler`, który jest typem funkcji przyjmującej wartość boolowską (prawda/fałsz). Jest on wykorzystywany do wstrzyknięcia logiki akceptacji notatki, która wymaga kilku operacji w logice klasy obsługującej przyjmowanie zaproszeń. Dzięki takiemu podejściu tworzymy luźną zależność do skomplikowanego obiektu na dalszych etapach systemu. `NoteInvitation` zawiera również metody `accept()` oraz `decline()`, które odpowiadają za wykonanie akcji zaproszenia, które pod spodem odpowiednio używają parametru `invitationHandler`, który można wykonać tylko raz, ze względu na specyfikę `Multipeer Connectivity`, a następnie usuwamy go z pamięci. + +```swift +struct NoteInvitation: Identifiable { + struct NoteContent: Codable { + let title: String + let noteSnapshot: String + } + + var id: MCPeerID { invitatorID } + var noteName: String { note.title } + let invitatorID: MCPeerID + let note: NoteContent + private var invitationHandler: ((Bool) -> Void)? + + init( + invitatorID: MCPeerID, + note: NoteContent, + invitationHandler: ((Bool) -> Void)? = nil + ) { + self.invitatorID = invitatorID + self.note = note + self.invitationHandler = invitationHandler + } + + mutating func accept() { + invitationHandler?(true) + invitationHandler = nil + } + + mutating func decline() { + invitationHandler?(false) + invitationHandler = nil + } +} +``` + +Ostatnim obiektem jest struktura `Peer`, która jest opisem aktualnego stanu połączenia wykrytego innej instancji systemu w pobliżu użytkownika. + == Warstwa sieciowa i komunikacja P2P + + == Odkrywanie innych urządzeń == Transportowanie danych == Algorytm rozwiązywania konfliktów diff --git a/Thesis/main.pdf b/Thesis/main.pdf index a593df2..245db17 100644 --- a/Thesis/main.pdf +++ b/Thesis/main.pdf @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4cb5f37fe4c2f1b44599430d4851dd7895b70341ce55a4a4125c47adc5a65ca1 -size 283522 +oid sha256:beaf055beb7723003b64ec035ddf2fdd2efbc29a2f975c873a224f7e8547b183 +size 313693