Orbit background info

We are on a mission to empower every university student the ability to find and approach other people who share similar interests. Ultimately helping each one of us create lifelong friendships. At its core, Orbit is an iOS consumer social app that addresses the isolation people feel despite living in a highly connected world. Its goal is to create a community where users—referred to as “astronauts”—can explore social connections, make friends, and feel a sense of belonging. It targets first-year univeristy students seeking to meet new people and build genuine relationships in a safe, personalized, and engaging environment.

Development

Architecture: MVVM + Services

The project uses the MVVM architecture with Services for backend calls where:

  1. Model (M): Enforces data types for data coming in and going to the database.
  2. View (V): Is the frontend graphic user interface (GUI/screen) the user interacts with.
  3. ViewModel (VM): Connects the Model to View ensuring the screens are redrawn with the data loaded in the ViewModel changes.
  4. Service: Are backend calls to the Appwrite database.

Example

Model

struct UserModel {
    let accountId: String
    let name: String
 
    init(accountId: String, name: String){
        self.accountId = accountId
        self.name = name
    }
}
 
typealias UserDocument = AppwriteModels.Document<UserModel>

View

struct UserView: View {
    // The ViewModels are declared at the App.swift level as follows:
    // @StateObject var userVM = UserViewModel()
 
    // To use a ViewModel in a screen add the following line
    @EnvironmentObject private var userVM: UserViewModel
 
    var body: some View {
        VStack {
            Text(userVM.currentUser.name)
            Button("Update Name") {
                userVM.updateUser("New Name")
            }
        }
    }
}

ViewModel

class UserViewModel {
   @Published var currentUser: UserModel?
 
   private var userService = UserService()
   @MainActor
   func updateUser(accountId: String, updatedUser: UserModel) async {
 
     guard let updatedUserDocument = try await userService.updateUser(
                 accountId: accountId, updatedUser: updatedUser)
     else {
         throw NSError(domain: "User not found", code: 404, userInfo: nil)
     }
 
     if id == currentUser?.accountId {
           // Update the currentUser
           self.currentUser = updatedUser
     }
   }
}

Service

import Appwrite
 
class UserService {
 
    func getUser(_ accountId: String) async throws -> UserDocument? {
        let query = Query.equal(
            "accountId",
            value: accountId
        )  // Query by accountId
        let response = try await appwriteService.databases.listDocuments<
            UserModel
        >(
            databaseId: appwriteService.databaseId,
            collectionId: collectionId,
            queries: [query],
            nestedType: UserModel.self
 
        )
        // Check if any document was found
        if let document = response.documents.first {
            return document
        } else {
            throw NSError(domain: "User not found", code: 404, userInfo: nil)
        }
    }
 
    func updateUser(accountId: String, updatedUser: UserModel) async throws -> UserDocument?
        {
        // Step (1): Find the documentId based on accountId
        guard let userDocument = try await getUser(accountId) else {
            print("Cannot update user")
            return nil
        }
 
        let documentId = userDocument.id
 
        // Step (2): Perform update using the documentId
        let updatedDocument = try await appwriteService.databases
            .updateDocument<UserModel>(
                databaseId: appwriteService.databaseId,
                collectionId: collectionId,
                documentId: documentId,
                data: updatedUser.toJson(),
                permissions: nil,
                nestedType: UserModel.self
            )
        return updatedDocument
    }
}