···618618 _ -> #(model, effect.none())
619619 }
620620 }
621621- Ok(OwnUserInformationResponse(username:, email:, avatar:, uuid:)) -> {
621621+ Ok(OwnUserInformationResponse(
622622+ username:,
623623+ email:,
624624+ avatar:,
625625+ uuid:,
626626+ unread_notifications:,
627627+ )) -> {
622628 // avatar is Option(#(String, String)) == Option((mime, base64))
623629 let avatar_string = case avatar {
624630 Some(#(mime, b64)) -> "data:" <> mime <> ";base64," <> b64
···641647 Model(
642648 ..model,
643649 cache: model_type.Cached(..model.cache, cached_users: new_users),
644644- user: Some(model_type.User(username, email, avatar_string)),
650650+ user: Some(model_type.UserSubmodel(
651651+ uid: uuid,
652652+ username:,
653653+ email:,
654654+ avatar: avatar_string,
655655+ notifs: model_type.NotificationsSubModel(
656656+ unread_count: unread_notifications,
657657+ cached_notifications: [],
658658+ ),
659659+ )),
645660 ),
646661 effect.none(),
647662 )
···870885 // Optional field populated with mime type and base64 of a profile picture.
871886 avatar: option.Option(#(String, String)),
872887 uuid: String,
888888+ /// Number of unread notifications, a timeline request for "notifications" can be used to get the actual notifications and fill the cache.
889889+ unread_notifications: Int,
873890 )
874891 Undecodable
875892}
···9981015 "own_user_information_response" -> {
9991016 use username <- decode.field("username", decode.string)
10001017 use email <- decode.field("email", decode.string)
10181018+ use unread_notifications <- decode.field(
10191019+ "unread_notifications",
10201020+ decode.int,
10211021+ )
10011022 // avatar may be null or an array [mime, base64]
10021023 use avatar_list_opt <- decode.field(
10031024 "avatar",
···10171038 email:,
10181039 avatar:,
10191040 uuid:,
10411041+ unread_notifications:,
10201042 ))
10211043 }
10221044 g -> {
+25-5
client/src/lumina_client/model_type.gleam
···3131 /// Page currently browsing.
3232 page: Page,
3333 /// User, if known
3434- user: Option(User),
3434+ user: Option(UserSubmodel),
3535 /// WebSocket connection
3636 ws: WsConnectionStatus,
3737 /// Used to restore sessions
···5050 /// If send_refresh_request(), it will update this value. If the last refresh request was over 30 seconds ago,
5151 /// the client will send a new refresh request to the server.
5252 last_refresh_request_time: Int,
5353+ )
5454+}
5555+5656+pub type NotificationsSubModel {
5757+ NotificationsSubModel(
5858+ /// Unread notifications count, calculated by the server based on the last time the user checked notifications
5959+ unread_count: Int,
6060+ /// Cached notifications
6161+ cached_notifications: List(Nil),
5362 )
5463}
5564···316325 LoginFields(emailfield: String, passwordfield: String)
317326}
318327319319-/// # User
328328+/// # User submodel
320329///
321330/// The User type is a struct that holds the user's data. It's an Option in the Model because the user might not be logged in.
322331/// Authentication STATUS is not stored in the Model, but in the websocket connection (the token is). The user is only stored in the Model for the UI to easy displaying the user's data.
323323-pub type User {
324324- User(username: String, email: String, avatar: String)
332332+pub type UserSubmodel {
333333+ UserSubmodel(
334334+ /// User ID (uuid)
335335+ uid: String,
336336+ /// Username
337337+ username: String,
338338+ /// Email
339339+ email: String,
340340+ /// Avatar as uri string, either a full URL or a base64-encoded 'data:'-string
341341+ avatar: String,
342342+ /// Notifications
343343+ notifs: NotificationsSubModel,
344344+ )
325345}
326346327347pub type SerializableModel {
···358378}
359379360380pub fn serialize(normal_model: Model) {
361361- let Model(page, _, _, token, _, _, _, _): Model = normal_model
381381+ let Model(page:, token:, ..): Model = normal_model
362382 SerializableModel(page:, token:)
363383 |> serialize_serializable_model
364384 |> json.to_string
···335335 STANDARD.encode(include_bytes!("../../assets/svgs/dummy_user_120px.svg")),
336336 )),
337337 uuid: user.id.to_string(),
338338+ //TODO: Fetch actual unread notification count
339339+ //Based on how many notifications are younger than last time user checked notifications. (WsMessage is sent when user opens notifications)
340340+ unread_notifications: 11
338341 };
339342 let msg_json = msgtojson(response);
340343 // println!("Sending own user information response: {}", msg_json);
···503506 // Optional field populated with mime type and base64 of a profile picture.
504507 avatar: Option<(String, String)>,
505508 uuid: String,
509509+ unread_notifications: u64,
506510 },
507511 /// Requests a list of strings to represent a certain timeline or bubble timeline.
508512 #[serde(rename = "timeline_request")]