From c8c2408663493cb369feea556a441da062d9979d Mon Sep 17 00:00:00 2001 From: Brandon McAnsh Date: Tue, 6 Oct 2026 12:37:54 -0400 Subject: [PATCH 1/2] chore(contract): sync flipcash2 protos to 9d44350 --- .../ContractInfo.swift | 2 +- .../blob_v1_model.pb.swift | 8 +- .../chat_v1_chat_service.grpc.swift | 778 ++++++++++++++++- .../chat_v1_chat_service.pb.swift | 780 ++++++++++++++++-- .../chat_v1_model.pb.swift | 433 ++++++++-- flipcash2.lock | 4 +- proto/blob/v1/model.proto | 4 +- proto/chat/v1/chat_service.proto | 281 ++++++- proto/chat/v1/model.proto | 118 ++- 9 files changed, 2164 insertions(+), 244 deletions(-) diff --git a/Sources/Flipcash2ClientProtocol/ContractInfo.swift b/Sources/Flipcash2ClientProtocol/ContractInfo.swift index c054b99..52aec29 100644 --- a/Sources/Flipcash2ClientProtocol/ContractInfo.swift +++ b/Sources/Flipcash2ClientProtocol/ContractInfo.swift @@ -2,7 +2,7 @@ public enum Flipcash2ContractInfo { public static let version = "0.17.0-dev" - public static let protoCommit = "3bb442d359dd8452b4e3eca5f5c1ca463e7f5a4b" + public static let protoCommit = "9d44350b8d4d8eda9d63cff405238bd0e2920409" public static var isLocal: Bool { protoCommit == localSentinel } diff --git a/Sources/Flipcash2ClientProtocol/blob_v1_model.pb.swift b/Sources/Flipcash2ClientProtocol/blob_v1_model.pb.swift index 88799d9..97c4292 100644 --- a/Sources/Flipcash2ClientProtocol/blob_v1_model.pb.swift +++ b/Sources/Flipcash2ClientProtocol/blob_v1_model.pb.swift @@ -823,8 +823,8 @@ public struct Flipcash_Blob_V1_AccessContext: Sendable { /// The caller is accessing these blobs from this chat's public profile. /// Authorized iff the blob is a rendition of that chat's CURRENT profile - /// picture — a profile grants nothing else, and a superseded picture's - /// renditions stop resolving through it. + /// picture or cover picture — a profile grants nothing else, and a + /// superseded picture's renditions stop resolving through it. public var chatProfile: Flipcash_Common_V1_ChatId { get { if case .chatProfile(let v)? = scope {return v} @@ -852,8 +852,8 @@ public struct Flipcash_Blob_V1_AccessContext: Sendable { case userProfile(Flipcash_Common_V1_UserId) /// The caller is accessing these blobs from this chat's public profile. /// Authorized iff the blob is a rendition of that chat's CURRENT profile - /// picture — a profile grants nothing else, and a superseded picture's - /// renditions stop resolving through it. + /// picture or cover picture — a profile grants nothing else, and a + /// superseded picture's renditions stop resolving through it. case chatProfile(Flipcash_Common_V1_ChatId) } diff --git a/Sources/Flipcash2ClientProtocol/chat_v1_chat_service.grpc.swift b/Sources/Flipcash2ClientProtocol/chat_v1_chat_service.grpc.swift index 70c2d3f..a07c649 100644 --- a/Sources/Flipcash2ClientProtocol/chat_v1_chat_service.grpc.swift +++ b/Sources/Flipcash2ClientProtocol/chat_v1_chat_service.grpc.swift @@ -68,6 +68,18 @@ public enum Flipcash_Chat_V1_Chat { method: "GetRoster" ) } + /// Namespace for "SampleChatters" metadata. + public enum SampleChatters { + /// Request type for "SampleChatters". + public typealias Input = Flipcash_Chat_V1_SampleChattersRequest + /// Response type for "SampleChatters". + public typealias Output = Flipcash_Chat_V1_SampleChattersResponse + /// Descriptor for "SampleChatters". + public static let descriptor = GRPCCore.MethodDescriptor( + service: GRPCCore.ServiceDescriptor(fullyQualifiedService: "flipcash.chat.v1.Chat"), + method: "SampleChatters" + ) + } /// Namespace for "GetMentionSuggestions" metadata. public enum GetMentionSuggestions { /// Request type for "GetMentionSuggestions". @@ -236,12 +248,37 @@ public enum Flipcash_Chat_V1_Chat { method: "GetKeyEnvelope" ) } + /// Namespace for "SetFeaturedGroups" metadata. + public enum SetFeaturedGroups { + /// Request type for "SetFeaturedGroups". + public typealias Input = Flipcash_Chat_V1_SetFeaturedGroupsRequest + /// Response type for "SetFeaturedGroups". + public typealias Output = Flipcash_Chat_V1_SetFeaturedGroupsResponse + /// Descriptor for "SetFeaturedGroups". + public static let descriptor = GRPCCore.MethodDescriptor( + service: GRPCCore.ServiceDescriptor(fullyQualifiedService: "flipcash.chat.v1.Chat"), + method: "SetFeaturedGroups" + ) + } + /// Namespace for "GetFeaturedGroups" metadata. + public enum GetFeaturedGroups { + /// Request type for "GetFeaturedGroups". + public typealias Input = Flipcash_Chat_V1_GetFeaturedGroupsRequest + /// Response type for "GetFeaturedGroups". + public typealias Output = Flipcash_Chat_V1_GetFeaturedGroupsResponse + /// Descriptor for "GetFeaturedGroups". + public static let descriptor = GRPCCore.MethodDescriptor( + service: GRPCCore.ServiceDescriptor(fullyQualifiedService: "flipcash.chat.v1.Chat"), + method: "GetFeaturedGroups" + ) + } /// Descriptors for all methods in the "flipcash.chat.v1.Chat" service. public static let descriptors: [GRPCCore.MethodDescriptor] = [ GetChat.descriptor, GetDmChatFeed.descriptor, GetGroupChatFeed.descriptor, GetRoster.descriptor, + SampleChatters.descriptor, GetMentionSuggestions.descriptor, StartChat.descriptor, JoinChat.descriptor, @@ -255,7 +292,9 @@ public enum Flipcash_Chat_V1_Chat { AdmitLobbyMember.descriptor, DenyLobbyMember.descriptor, SetKeyEnvelope.descriptor, - GetKeyEnvelope.descriptor + GetKeyEnvelope.descriptor, + SetFeaturedGroups.descriptor, + GetFeaturedGroups.descriptor ] } } @@ -382,6 +421,10 @@ extension Flipcash_Chat_V1_Chat { /// > being read. Every page is served only for groups the caller is still a /// > member of at the time of that page; a group the caller left between /// > pages is dropped, and its removal arrives on the stream. + /// > + /// > The feed is meant for list views, so a chat's cover_picture may be + /// > omitted from it (see Metadata). Fetch it with GetChat when the client + /// > shows the chat's profile view. /// /// - Parameters: /// - request: A request containing a single `Flipcash_Chat_V1_GetGroupChatFeedRequest` message. @@ -428,9 +471,9 @@ extension Flipcash_Chat_V1_Chat { /// > carry none: group pointer advances are never broadcast, so a page of /// > them would be stale as soon as it was served. /// > - /// > Requires that the caller may read the chat: a member, or a non-member - /// > a group's listener rules admit. A viewer who may only preview the chat - /// > is DENIED. + /// > Requires that the caller is a member of the chat. Anyone else is + /// > DENIED, including a non-member whom a group's listener rules admit to + /// > read its messages: who is in a chat is shown only to its members. /// /// - Parameters: /// - request: A request containing a single `Flipcash_Chat_V1_GetRosterRequest` message. @@ -449,6 +492,61 @@ extension Flipcash_Chat_V1_Chat { onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse) async throws -> Result ) async throws -> Result where Result: Sendable + /// Call the "SampleChatters" method. + /// + /// > Source IDL Documentation: + /// > + /// > SampleChatters returns a short sample of a public group's members to + /// > show: its creator first, while they are a member, then the members who + /// > have sent a message most recently, most recent first. Members who have + /// > not sent a message recently are not in it. The caller is included like + /// > any other member, and so are users the caller has blocked: the sample + /// > shows who is in the chat, not who may be mentioned (see + /// > GetMentionSuggestions). + /// > + /// > Unlike the roster (see GetRoster), the sample is public: it is part of + /// > how a group presents itself, as its title and pictures are, and is + /// > returned to anyone who asks, member or not, registered or not. Auth is + /// > optional; when set it must be valid, but it changes nothing about what + /// > is returned. + /// > + /// > Everyone in the sample is a member of the group as of the read, which + /// > may trail a join or departure by a moment: it is a subset of the roster + /// > GetRoster pages, never someone who never joined, though someone who + /// > left a moment ago may still be in it. It is not the whole roster: it is neither complete nor + /// > paged and carries no roster version, and has_more is the only + /// > indication of what lies past it. The server decides how many to + /// > return, up to 100; neither the size nor the order after the creator is + /// > part of the contract. + /// > + /// > It is a snapshot, which a client may show as it is. A client that wants + /// > it live, and streams the group's events (as a member, or through a chat + /// > preview), may instead keep it fresh between fetches by moving the + /// > sender of each new message to the front, adding them if absent, since + /// > anyone who sends is a member. Departures are not announced to the other + /// > members (see RosterUpdate.MembershipChanged), so a member who has left + /// > may remain in a client's copy until it fetches again. + /// > + /// > Only for public groups: a private group (see Metadata.is_private) and a + /// > DM are DENIED, whoever asks. + /// + /// - Parameters: + /// - request: A request containing a single `Flipcash_Chat_V1_SampleChattersRequest` message. + /// - serializer: A serializer for `Flipcash_Chat_V1_SampleChattersRequest` messages. + /// - deserializer: A deserializer for `Flipcash_Chat_V1_SampleChattersResponse` messages. + /// - options: Options to apply to this RPC. + /// - handleResponse: A closure which handles the response, the result of which is + /// returned to the caller. Returning from the closure will cancel the RPC if it + /// hasn't already finished. + /// - Returns: The result of `handleResponse`. + func sampleChatters( + request: GRPCCore.ClientRequest, + serializer: some GRPCCore.MessageSerializer, + deserializer: some GRPCCore.MessageDeserializer, + options: GRPCCore.CallOptions, + onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse) async throws -> Result + ) async throws -> Result where Result: Sendable + /// Call the "GetMentionSuggestions" method. /// /// > Source IDL Documentation: @@ -579,17 +677,18 @@ extension Flipcash_Chat_V1_Chat { /// > Only a group chat may be edited, and only by a member the server permits /// > to edit it, as reported by ViewerState.Permissions.can_edit; anyone else /// > is DENIED. A new title or description is moderated like StartChat's. A - /// > new picture is a blob the caller has already uploaded via - /// > BlobStorage: the client uploads only the ORIGINAL and passes the - /// > resulting BlobId once the blob is READY, and the server derives the - /// > remaining renditions. Setting a field to the value the chat already has - /// > is a no-op for that field, and a request that sets nothing is a no-op - /// > that returns OK. + /// > new profile picture or cover picture is a blob the caller has already + /// > uploaded via BlobStorage: the client uploads only the ORIGINAL and + /// > passes the resulting BlobId once the blob is READY, and the server + /// > derives the remaining renditions. Setting a field to the value the chat + /// > already has is a no-op for that field, and a request that sets nothing + /// > is a no-op that returns OK. /// > /// > Every real change reaches the chat's members, including the caller's /// > other devices, on the event stream as one MetadataUpdate per field - /// > changed: TitleChanged for the title, PictureChanged for the picture, - /// > DescriptionChanged for the description. + /// > changed: TitleChanged for the title, ProfilePictureChanged for the + /// > profile picture, DescriptionChanged for the description, + /// > CoverPictureChanged for the cover picture. /// /// - Parameters: /// - request: A request containing a single `Flipcash_Chat_V1_EditChatRequest` message. @@ -912,6 +1011,88 @@ extension Flipcash_Chat_V1_Chat { options: GRPCCore.CallOptions, onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse) async throws -> Result ) async throws -> Result where Result: Sendable + + /// Call the "SetFeaturedGroups" method. + /// + /// > Source IDL Documentation: + /// > + /// > SetFeaturedGroups replaces the caller's featured groups: an ordered + /// > list of public group chats they show on their profile, which anyone can + /// > fetch with GetFeaturedGroups. The list is written whole, so the request + /// > carries every group the caller wants featured, in the order to show + /// > them, and an empty list clears it. Setting the list already stored is a + /// > no-op that returns OK. + /// > + /// > Featuring a group says nothing about the caller's place in it: a group + /// > may be featured whether or not the caller is a member, and leaving a + /// > group does not remove it from the list. + /// > + /// > Only public groups may be featured: when a group in the request is + /// > private (see Metadata.is_private), nothing is written and the result + /// > is DENIED. A group never becomes private after it is created, so a + /// > featured group stays public. Every group must exist: when one does not, + /// > nothing is written and the result is NOT_FOUND. A DM's ID, or a group + /// > named more than once, is an invalid argument. + /// > + /// > Nothing is published: the caller's other devices see the change on + /// > their next GetFeaturedGroups. + /// + /// - Parameters: + /// - request: A request containing a single `Flipcash_Chat_V1_SetFeaturedGroupsRequest` message. + /// - serializer: A serializer for `Flipcash_Chat_V1_SetFeaturedGroupsRequest` messages. + /// - deserializer: A deserializer for `Flipcash_Chat_V1_SetFeaturedGroupsResponse` messages. + /// - options: Options to apply to this RPC. + /// - handleResponse: A closure which handles the response, the result of which is + /// returned to the caller. Returning from the closure will cancel the RPC if it + /// hasn't already finished. + /// - Returns: The result of `handleResponse`. + func setFeaturedGroups( + request: GRPCCore.ClientRequest, + serializer: some GRPCCore.MessageSerializer, + deserializer: some GRPCCore.MessageDeserializer, + options: GRPCCore.CallOptions, + onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse) async throws -> Result + ) async throws -> Result where Result: Sendable + + /// Call the "GetFeaturedGroups" method. + /// + /// > Source IDL Documentation: + /// > + /// > GetFeaturedGroups returns a user's featured groups (see + /// > SetFeaturedGroups), in the order the user set them. + /// > + /// > Each group is a public group (see SetFeaturedGroups), returned as its + /// > record as a list view shows it: chat_id, type, title, description, + /// > profile_picture, roster_summary, rules, creator and last_activity. Nothing about the viewer's place in the + /// > group is set (members, is_hidden, viewer_state, in_lobby), nor its + /// > messaging state (last_message, latest_event_sequence), nor its + /// > cover_picture: a client opening a group fetches the rest with GetChat. + /// > + /// > The list is public, like the user's profile, and the same for every + /// > viewer. Auth is optional; when set it must be valid, but it changes + /// > nothing about what is returned. A group that no longer exists is left + /// > out. + /// > + /// > The user is identified by username, the handle a profile is opened by, + /// > so a client can fetch a profile (see profile.v1.Profile.GetProfile) and + /// > its featured groups at once. + /// + /// - Parameters: + /// - request: A request containing a single `Flipcash_Chat_V1_GetFeaturedGroupsRequest` message. + /// - serializer: A serializer for `Flipcash_Chat_V1_GetFeaturedGroupsRequest` messages. + /// - deserializer: A deserializer for `Flipcash_Chat_V1_GetFeaturedGroupsResponse` messages. + /// - options: Options to apply to this RPC. + /// - handleResponse: A closure which handles the response, the result of which is + /// returned to the caller. Returning from the closure will cancel the RPC if it + /// hasn't already finished. + /// - Returns: The result of `handleResponse`. + func getFeaturedGroups( + request: GRPCCore.ClientRequest, + serializer: some GRPCCore.MessageSerializer, + deserializer: some GRPCCore.MessageDeserializer, + options: GRPCCore.CallOptions, + onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse) async throws -> Result + ) async throws -> Result where Result: Sendable } /// Generated client for the "flipcash.chat.v1.Chat" service. @@ -1059,6 +1240,10 @@ extension Flipcash_Chat_V1_Chat { /// > being read. Every page is served only for groups the caller is still a /// > member of at the time of that page; a group the caller left between /// > pages is dropped, and its removal arrives on the stream. + /// > + /// > The feed is meant for list views, so a chat's cover_picture may be + /// > omitted from it (see Metadata). Fetch it with GetChat when the client + /// > shows the chat's profile view. /// /// - Parameters: /// - request: A request containing a single `Flipcash_Chat_V1_GetGroupChatFeedRequest` message. @@ -1116,9 +1301,9 @@ extension Flipcash_Chat_V1_Chat { /// > carry none: group pointer advances are never broadcast, so a page of /// > them would be stale as soon as it was served. /// > - /// > Requires that the caller may read the chat: a member, or a non-member - /// > a group's listener rules admit. A viewer who may only preview the chat - /// > is DENIED. + /// > Requires that the caller is a member of the chat. Anyone else is + /// > DENIED, including a non-member whom a group's listener rules admit to + /// > read its messages: who is in a chat is shown only to its members. /// /// - Parameters: /// - request: A request containing a single `Flipcash_Chat_V1_GetRosterRequest` message. @@ -1148,6 +1333,72 @@ extension Flipcash_Chat_V1_Chat { ) } + /// Call the "SampleChatters" method. + /// + /// > Source IDL Documentation: + /// > + /// > SampleChatters returns a short sample of a public group's members to + /// > show: its creator first, while they are a member, then the members who + /// > have sent a message most recently, most recent first. Members who have + /// > not sent a message recently are not in it. The caller is included like + /// > any other member, and so are users the caller has blocked: the sample + /// > shows who is in the chat, not who may be mentioned (see + /// > GetMentionSuggestions). + /// > + /// > Unlike the roster (see GetRoster), the sample is public: it is part of + /// > how a group presents itself, as its title and pictures are, and is + /// > returned to anyone who asks, member or not, registered or not. Auth is + /// > optional; when set it must be valid, but it changes nothing about what + /// > is returned. + /// > + /// > Everyone in the sample is a member of the group as of the read, which + /// > may trail a join or departure by a moment: it is a subset of the roster + /// > GetRoster pages, never someone who never joined, though someone who + /// > left a moment ago may still be in it. It is not the whole roster: it is neither complete nor + /// > paged and carries no roster version, and has_more is the only + /// > indication of what lies past it. The server decides how many to + /// > return, up to 100; neither the size nor the order after the creator is + /// > part of the contract. + /// > + /// > It is a snapshot, which a client may show as it is. A client that wants + /// > it live, and streams the group's events (as a member, or through a chat + /// > preview), may instead keep it fresh between fetches by moving the + /// > sender of each new message to the front, adding them if absent, since + /// > anyone who sends is a member. Departures are not announced to the other + /// > members (see RosterUpdate.MembershipChanged), so a member who has left + /// > may remain in a client's copy until it fetches again. + /// > + /// > Only for public groups: a private group (see Metadata.is_private) and a + /// > DM are DENIED, whoever asks. + /// + /// - Parameters: + /// - request: A request containing a single `Flipcash_Chat_V1_SampleChattersRequest` message. + /// - serializer: A serializer for `Flipcash_Chat_V1_SampleChattersRequest` messages. + /// - deserializer: A deserializer for `Flipcash_Chat_V1_SampleChattersResponse` messages. + /// - options: Options to apply to this RPC. + /// - handleResponse: A closure which handles the response, the result of which is + /// returned to the caller. Returning from the closure will cancel the RPC if it + /// hasn't already finished. + /// - Returns: The result of `handleResponse`. + public func sampleChatters( + request: GRPCCore.ClientRequest, + serializer: some GRPCCore.MessageSerializer, + deserializer: some GRPCCore.MessageDeserializer, + options: GRPCCore.CallOptions = .defaults, + onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse) async throws -> Result = { response in + try response.message + } + ) async throws -> Result where Result: Sendable { + try await self.client.unary( + request: request, + descriptor: Flipcash_Chat_V1_Chat.Method.SampleChatters.descriptor, + serializer: serializer, + deserializer: deserializer, + options: options, + onResponse: handleResponse + ) + } + /// Call the "GetMentionSuggestions" method. /// /// > Source IDL Documentation: @@ -1322,17 +1573,18 @@ extension Flipcash_Chat_V1_Chat { /// > Only a group chat may be edited, and only by a member the server permits /// > to edit it, as reported by ViewerState.Permissions.can_edit; anyone else /// > is DENIED. A new title or description is moderated like StartChat's. A - /// > new picture is a blob the caller has already uploaded via - /// > BlobStorage: the client uploads only the ORIGINAL and passes the - /// > resulting BlobId once the blob is READY, and the server derives the - /// > remaining renditions. Setting a field to the value the chat already has - /// > is a no-op for that field, and a request that sets nothing is a no-op - /// > that returns OK. + /// > new profile picture or cover picture is a blob the caller has already + /// > uploaded via BlobStorage: the client uploads only the ORIGINAL and + /// > passes the resulting BlobId once the blob is READY, and the server + /// > derives the remaining renditions. Setting a field to the value the chat + /// > already has is a no-op for that field, and a request that sets nothing + /// > is a no-op that returns OK. /// > /// > Every real change reaches the chat's members, including the caller's /// > other devices, on the event stream as one MetadataUpdate per field - /// > changed: TitleChanged for the title, PictureChanged for the picture, - /// > DescriptionChanged for the description. + /// > changed: TitleChanged for the title, ProfilePictureChanged for the + /// > profile picture, DescriptionChanged for the description, + /// > CoverPictureChanged for the cover picture. /// /// - Parameters: /// - request: A request containing a single `Flipcash_Chat_V1_EditChatRequest` message. @@ -1765,6 +2017,110 @@ extension Flipcash_Chat_V1_Chat { onResponse: handleResponse ) } + + /// Call the "SetFeaturedGroups" method. + /// + /// > Source IDL Documentation: + /// > + /// > SetFeaturedGroups replaces the caller's featured groups: an ordered + /// > list of public group chats they show on their profile, which anyone can + /// > fetch with GetFeaturedGroups. The list is written whole, so the request + /// > carries every group the caller wants featured, in the order to show + /// > them, and an empty list clears it. Setting the list already stored is a + /// > no-op that returns OK. + /// > + /// > Featuring a group says nothing about the caller's place in it: a group + /// > may be featured whether or not the caller is a member, and leaving a + /// > group does not remove it from the list. + /// > + /// > Only public groups may be featured: when a group in the request is + /// > private (see Metadata.is_private), nothing is written and the result + /// > is DENIED. A group never becomes private after it is created, so a + /// > featured group stays public. Every group must exist: when one does not, + /// > nothing is written and the result is NOT_FOUND. A DM's ID, or a group + /// > named more than once, is an invalid argument. + /// > + /// > Nothing is published: the caller's other devices see the change on + /// > their next GetFeaturedGroups. + /// + /// - Parameters: + /// - request: A request containing a single `Flipcash_Chat_V1_SetFeaturedGroupsRequest` message. + /// - serializer: A serializer for `Flipcash_Chat_V1_SetFeaturedGroupsRequest` messages. + /// - deserializer: A deserializer for `Flipcash_Chat_V1_SetFeaturedGroupsResponse` messages. + /// - options: Options to apply to this RPC. + /// - handleResponse: A closure which handles the response, the result of which is + /// returned to the caller. Returning from the closure will cancel the RPC if it + /// hasn't already finished. + /// - Returns: The result of `handleResponse`. + public func setFeaturedGroups( + request: GRPCCore.ClientRequest, + serializer: some GRPCCore.MessageSerializer, + deserializer: some GRPCCore.MessageDeserializer, + options: GRPCCore.CallOptions = .defaults, + onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse) async throws -> Result = { response in + try response.message + } + ) async throws -> Result where Result: Sendable { + try await self.client.unary( + request: request, + descriptor: Flipcash_Chat_V1_Chat.Method.SetFeaturedGroups.descriptor, + serializer: serializer, + deserializer: deserializer, + options: options, + onResponse: handleResponse + ) + } + + /// Call the "GetFeaturedGroups" method. + /// + /// > Source IDL Documentation: + /// > + /// > GetFeaturedGroups returns a user's featured groups (see + /// > SetFeaturedGroups), in the order the user set them. + /// > + /// > Each group is a public group (see SetFeaturedGroups), returned as its + /// > record as a list view shows it: chat_id, type, title, description, + /// > profile_picture, roster_summary, rules, creator and last_activity. Nothing about the viewer's place in the + /// > group is set (members, is_hidden, viewer_state, in_lobby), nor its + /// > messaging state (last_message, latest_event_sequence), nor its + /// > cover_picture: a client opening a group fetches the rest with GetChat. + /// > + /// > The list is public, like the user's profile, and the same for every + /// > viewer. Auth is optional; when set it must be valid, but it changes + /// > nothing about what is returned. A group that no longer exists is left + /// > out. + /// > + /// > The user is identified by username, the handle a profile is opened by, + /// > so a client can fetch a profile (see profile.v1.Profile.GetProfile) and + /// > its featured groups at once. + /// + /// - Parameters: + /// - request: A request containing a single `Flipcash_Chat_V1_GetFeaturedGroupsRequest` message. + /// - serializer: A serializer for `Flipcash_Chat_V1_GetFeaturedGroupsRequest` messages. + /// - deserializer: A deserializer for `Flipcash_Chat_V1_GetFeaturedGroupsResponse` messages. + /// - options: Options to apply to this RPC. + /// - handleResponse: A closure which handles the response, the result of which is + /// returned to the caller. Returning from the closure will cancel the RPC if it + /// hasn't already finished. + /// - Returns: The result of `handleResponse`. + public func getFeaturedGroups( + request: GRPCCore.ClientRequest, + serializer: some GRPCCore.MessageSerializer, + deserializer: some GRPCCore.MessageDeserializer, + options: GRPCCore.CallOptions = .defaults, + onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse) async throws -> Result = { response in + try response.message + } + ) async throws -> Result where Result: Sendable { + try await self.client.unary( + request: request, + descriptor: Flipcash_Chat_V1_Chat.Method.GetFeaturedGroups.descriptor, + serializer: serializer, + deserializer: deserializer, + options: options, + onResponse: handleResponse + ) + } } } @@ -1890,6 +2246,10 @@ extension Flipcash_Chat_V1_Chat.ClientProtocol { /// > being read. Every page is served only for groups the caller is still a /// > member of at the time of that page; a group the caller left between /// > pages is dropped, and its removal arrives on the stream. + /// > + /// > The feed is meant for list views, so a chat's cover_picture may be + /// > omitted from it (see Metadata). Fetch it with GetChat when the client + /// > shows the chat's profile view. /// /// - Parameters: /// - request: A request containing a single `Flipcash_Chat_V1_GetGroupChatFeedRequest` message. @@ -1942,9 +2302,9 @@ extension Flipcash_Chat_V1_Chat.ClientProtocol { /// > carry none: group pointer advances are never broadcast, so a page of /// > them would be stale as soon as it was served. /// > - /// > Requires that the caller may read the chat: a member, or a non-member - /// > a group's listener rules admit. A viewer who may only preview the chat - /// > is DENIED. + /// > Requires that the caller is a member of the chat. Anyone else is + /// > DENIED, including a non-member whom a group's listener rules admit to + /// > read its messages: who is in a chat is shown only to its members. /// /// - Parameters: /// - request: A request containing a single `Flipcash_Chat_V1_GetRosterRequest` message. @@ -1969,6 +2329,67 @@ extension Flipcash_Chat_V1_Chat.ClientProtocol { ) } + /// Call the "SampleChatters" method. + /// + /// > Source IDL Documentation: + /// > + /// > SampleChatters returns a short sample of a public group's members to + /// > show: its creator first, while they are a member, then the members who + /// > have sent a message most recently, most recent first. Members who have + /// > not sent a message recently are not in it. The caller is included like + /// > any other member, and so are users the caller has blocked: the sample + /// > shows who is in the chat, not who may be mentioned (see + /// > GetMentionSuggestions). + /// > + /// > Unlike the roster (see GetRoster), the sample is public: it is part of + /// > how a group presents itself, as its title and pictures are, and is + /// > returned to anyone who asks, member or not, registered or not. Auth is + /// > optional; when set it must be valid, but it changes nothing about what + /// > is returned. + /// > + /// > Everyone in the sample is a member of the group as of the read, which + /// > may trail a join or departure by a moment: it is a subset of the roster + /// > GetRoster pages, never someone who never joined, though someone who + /// > left a moment ago may still be in it. It is not the whole roster: it is neither complete nor + /// > paged and carries no roster version, and has_more is the only + /// > indication of what lies past it. The server decides how many to + /// > return, up to 100; neither the size nor the order after the creator is + /// > part of the contract. + /// > + /// > It is a snapshot, which a client may show as it is. A client that wants + /// > it live, and streams the group's events (as a member, or through a chat + /// > preview), may instead keep it fresh between fetches by moving the + /// > sender of each new message to the front, adding them if absent, since + /// > anyone who sends is a member. Departures are not announced to the other + /// > members (see RosterUpdate.MembershipChanged), so a member who has left + /// > may remain in a client's copy until it fetches again. + /// > + /// > Only for public groups: a private group (see Metadata.is_private) and a + /// > DM are DENIED, whoever asks. + /// + /// - Parameters: + /// - request: A request containing a single `Flipcash_Chat_V1_SampleChattersRequest` message. + /// - options: Options to apply to this RPC. + /// - handleResponse: A closure which handles the response, the result of which is + /// returned to the caller. Returning from the closure will cancel the RPC if it + /// hasn't already finished. + /// - Returns: The result of `handleResponse`. + public func sampleChatters( + request: GRPCCore.ClientRequest, + options: GRPCCore.CallOptions = .defaults, + onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse) async throws -> Result = { response in + try response.message + } + ) async throws -> Result where Result: Sendable { + try await self.sampleChatters( + request: request, + serializer: GRPCProtobuf.ProtobufSerializer(), + deserializer: GRPCProtobuf.ProtobufDeserializer(), + options: options, + onResponse: handleResponse + ) + } + /// Call the "GetMentionSuggestions" method. /// /// > Source IDL Documentation: @@ -2123,17 +2544,18 @@ extension Flipcash_Chat_V1_Chat.ClientProtocol { /// > Only a group chat may be edited, and only by a member the server permits /// > to edit it, as reported by ViewerState.Permissions.can_edit; anyone else /// > is DENIED. A new title or description is moderated like StartChat's. A - /// > new picture is a blob the caller has already uploaded via - /// > BlobStorage: the client uploads only the ORIGINAL and passes the - /// > resulting BlobId once the blob is READY, and the server derives the - /// > remaining renditions. Setting a field to the value the chat already has - /// > is a no-op for that field, and a request that sets nothing is a no-op - /// > that returns OK. + /// > new profile picture or cover picture is a blob the caller has already + /// > uploaded via BlobStorage: the client uploads only the ORIGINAL and + /// > passes the resulting BlobId once the blob is READY, and the server + /// > derives the remaining renditions. Setting a field to the value the chat + /// > already has is a no-op for that field, and a request that sets nothing + /// > is a no-op that returns OK. /// > /// > Every real change reaches the chat's members, including the caller's /// > other devices, on the event stream as one MetadataUpdate per field - /// > changed: TitleChanged for the title, PictureChanged for the picture, - /// > DescriptionChanged for the description. + /// > changed: TitleChanged for the title, ProfilePictureChanged for the + /// > profile picture, DescriptionChanged for the description, + /// > CoverPictureChanged for the cover picture. /// /// - Parameters: /// - request: A request containing a single `Flipcash_Chat_V1_EditChatRequest` message. @@ -2516,6 +2938,100 @@ extension Flipcash_Chat_V1_Chat.ClientProtocol { onResponse: handleResponse ) } + + /// Call the "SetFeaturedGroups" method. + /// + /// > Source IDL Documentation: + /// > + /// > SetFeaturedGroups replaces the caller's featured groups: an ordered + /// > list of public group chats they show on their profile, which anyone can + /// > fetch with GetFeaturedGroups. The list is written whole, so the request + /// > carries every group the caller wants featured, in the order to show + /// > them, and an empty list clears it. Setting the list already stored is a + /// > no-op that returns OK. + /// > + /// > Featuring a group says nothing about the caller's place in it: a group + /// > may be featured whether or not the caller is a member, and leaving a + /// > group does not remove it from the list. + /// > + /// > Only public groups may be featured: when a group in the request is + /// > private (see Metadata.is_private), nothing is written and the result + /// > is DENIED. A group never becomes private after it is created, so a + /// > featured group stays public. Every group must exist: when one does not, + /// > nothing is written and the result is NOT_FOUND. A DM's ID, or a group + /// > named more than once, is an invalid argument. + /// > + /// > Nothing is published: the caller's other devices see the change on + /// > their next GetFeaturedGroups. + /// + /// - Parameters: + /// - request: A request containing a single `Flipcash_Chat_V1_SetFeaturedGroupsRequest` message. + /// - options: Options to apply to this RPC. + /// - handleResponse: A closure which handles the response, the result of which is + /// returned to the caller. Returning from the closure will cancel the RPC if it + /// hasn't already finished. + /// - Returns: The result of `handleResponse`. + public func setFeaturedGroups( + request: GRPCCore.ClientRequest, + options: GRPCCore.CallOptions = .defaults, + onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse) async throws -> Result = { response in + try response.message + } + ) async throws -> Result where Result: Sendable { + try await self.setFeaturedGroups( + request: request, + serializer: GRPCProtobuf.ProtobufSerializer(), + deserializer: GRPCProtobuf.ProtobufDeserializer(), + options: options, + onResponse: handleResponse + ) + } + + /// Call the "GetFeaturedGroups" method. + /// + /// > Source IDL Documentation: + /// > + /// > GetFeaturedGroups returns a user's featured groups (see + /// > SetFeaturedGroups), in the order the user set them. + /// > + /// > Each group is a public group (see SetFeaturedGroups), returned as its + /// > record as a list view shows it: chat_id, type, title, description, + /// > profile_picture, roster_summary, rules, creator and last_activity. Nothing about the viewer's place in the + /// > group is set (members, is_hidden, viewer_state, in_lobby), nor its + /// > messaging state (last_message, latest_event_sequence), nor its + /// > cover_picture: a client opening a group fetches the rest with GetChat. + /// > + /// > The list is public, like the user's profile, and the same for every + /// > viewer. Auth is optional; when set it must be valid, but it changes + /// > nothing about what is returned. A group that no longer exists is left + /// > out. + /// > + /// > The user is identified by username, the handle a profile is opened by, + /// > so a client can fetch a profile (see profile.v1.Profile.GetProfile) and + /// > its featured groups at once. + /// + /// - Parameters: + /// - request: A request containing a single `Flipcash_Chat_V1_GetFeaturedGroupsRequest` message. + /// - options: Options to apply to this RPC. + /// - handleResponse: A closure which handles the response, the result of which is + /// returned to the caller. Returning from the closure will cancel the RPC if it + /// hasn't already finished. + /// - Returns: The result of `handleResponse`. + public func getFeaturedGroups( + request: GRPCCore.ClientRequest, + options: GRPCCore.CallOptions = .defaults, + onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse) async throws -> Result = { response in + try response.message + } + ) async throws -> Result where Result: Sendable { + try await self.getFeaturedGroups( + request: request, + serializer: GRPCProtobuf.ProtobufSerializer(), + deserializer: GRPCProtobuf.ProtobufDeserializer(), + options: options, + onResponse: handleResponse + ) + } } // Helpers providing sugared APIs for 'ClientProtocol' methods. @@ -2648,6 +3164,10 @@ extension Flipcash_Chat_V1_Chat.ClientProtocol { /// > being read. Every page is served only for groups the caller is still a /// > member of at the time of that page; a group the caller left between /// > pages is dropped, and its removal arrives on the stream. + /// > + /// > The feed is meant for list views, so a chat's cover_picture may be + /// > omitted from it (see Metadata). Fetch it with GetChat when the client + /// > shows the chat's profile view. /// /// - Parameters: /// - message: request message to send. @@ -2704,9 +3224,9 @@ extension Flipcash_Chat_V1_Chat.ClientProtocol { /// > carry none: group pointer advances are never broadcast, so a page of /// > them would be stale as soon as it was served. /// > - /// > Requires that the caller may read the chat: a member, or a non-member - /// > a group's listener rules admit. A viewer who may only preview the chat - /// > is DENIED. + /// > Requires that the caller is a member of the chat. Anyone else is + /// > DENIED, including a non-member whom a group's listener rules admit to + /// > read its messages: who is in a chat is shown only to its members. /// /// - Parameters: /// - message: request message to send. @@ -2735,6 +3255,71 @@ extension Flipcash_Chat_V1_Chat.ClientProtocol { ) } + /// Call the "SampleChatters" method. + /// + /// > Source IDL Documentation: + /// > + /// > SampleChatters returns a short sample of a public group's members to + /// > show: its creator first, while they are a member, then the members who + /// > have sent a message most recently, most recent first. Members who have + /// > not sent a message recently are not in it. The caller is included like + /// > any other member, and so are users the caller has blocked: the sample + /// > shows who is in the chat, not who may be mentioned (see + /// > GetMentionSuggestions). + /// > + /// > Unlike the roster (see GetRoster), the sample is public: it is part of + /// > how a group presents itself, as its title and pictures are, and is + /// > returned to anyone who asks, member or not, registered or not. Auth is + /// > optional; when set it must be valid, but it changes nothing about what + /// > is returned. + /// > + /// > Everyone in the sample is a member of the group as of the read, which + /// > may trail a join or departure by a moment: it is a subset of the roster + /// > GetRoster pages, never someone who never joined, though someone who + /// > left a moment ago may still be in it. It is not the whole roster: it is neither complete nor + /// > paged and carries no roster version, and has_more is the only + /// > indication of what lies past it. The server decides how many to + /// > return, up to 100; neither the size nor the order after the creator is + /// > part of the contract. + /// > + /// > It is a snapshot, which a client may show as it is. A client that wants + /// > it live, and streams the group's events (as a member, or through a chat + /// > preview), may instead keep it fresh between fetches by moving the + /// > sender of each new message to the front, adding them if absent, since + /// > anyone who sends is a member. Departures are not announced to the other + /// > members (see RosterUpdate.MembershipChanged), so a member who has left + /// > may remain in a client's copy until it fetches again. + /// > + /// > Only for public groups: a private group (see Metadata.is_private) and a + /// > DM are DENIED, whoever asks. + /// + /// - Parameters: + /// - message: request message to send. + /// - metadata: Additional metadata to send, defaults to empty. + /// - options: Options to apply to this RPC, defaults to `.defaults`. + /// - handleResponse: A closure which handles the response, the result of which is + /// returned to the caller. Returning from the closure will cancel the RPC if it + /// hasn't already finished. + /// - Returns: The result of `handleResponse`. + public func sampleChatters( + _ message: Flipcash_Chat_V1_SampleChattersRequest, + metadata: GRPCCore.Metadata = [:], + options: GRPCCore.CallOptions = .defaults, + onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse) async throws -> Result = { response in + try response.message + } + ) async throws -> Result where Result: Sendable { + let request = GRPCCore.ClientRequest( + message: message, + metadata: metadata + ) + return try await self.sampleChatters( + request: request, + options: options, + onResponse: handleResponse + ) + } + /// Call the "GetMentionSuggestions" method. /// /// > Source IDL Documentation: @@ -2905,17 +3490,18 @@ extension Flipcash_Chat_V1_Chat.ClientProtocol { /// > Only a group chat may be edited, and only by a member the server permits /// > to edit it, as reported by ViewerState.Permissions.can_edit; anyone else /// > is DENIED. A new title or description is moderated like StartChat's. A - /// > new picture is a blob the caller has already uploaded via - /// > BlobStorage: the client uploads only the ORIGINAL and passes the - /// > resulting BlobId once the blob is READY, and the server derives the - /// > remaining renditions. Setting a field to the value the chat already has - /// > is a no-op for that field, and a request that sets nothing is a no-op - /// > that returns OK. + /// > new profile picture or cover picture is a blob the caller has already + /// > uploaded via BlobStorage: the client uploads only the ORIGINAL and + /// > passes the resulting BlobId once the blob is READY, and the server + /// > derives the remaining renditions. Setting a field to the value the chat + /// > already has is a no-op for that field, and a request that sets nothing + /// > is a no-op that returns OK. /// > /// > Every real change reaches the chat's members, including the caller's /// > other devices, on the event stream as one MetadataUpdate per field - /// > changed: TitleChanged for the title, PictureChanged for the picture, - /// > DescriptionChanged for the description. + /// > changed: TitleChanged for the title, ProfilePictureChanged for the + /// > profile picture, DescriptionChanged for the description, + /// > CoverPictureChanged for the cover picture. /// /// - Parameters: /// - message: request message to send. @@ -3338,4 +3924,106 @@ extension Flipcash_Chat_V1_Chat.ClientProtocol { onResponse: handleResponse ) } + + /// Call the "SetFeaturedGroups" method. + /// + /// > Source IDL Documentation: + /// > + /// > SetFeaturedGroups replaces the caller's featured groups: an ordered + /// > list of public group chats they show on their profile, which anyone can + /// > fetch with GetFeaturedGroups. The list is written whole, so the request + /// > carries every group the caller wants featured, in the order to show + /// > them, and an empty list clears it. Setting the list already stored is a + /// > no-op that returns OK. + /// > + /// > Featuring a group says nothing about the caller's place in it: a group + /// > may be featured whether or not the caller is a member, and leaving a + /// > group does not remove it from the list. + /// > + /// > Only public groups may be featured: when a group in the request is + /// > private (see Metadata.is_private), nothing is written and the result + /// > is DENIED. A group never becomes private after it is created, so a + /// > featured group stays public. Every group must exist: when one does not, + /// > nothing is written and the result is NOT_FOUND. A DM's ID, or a group + /// > named more than once, is an invalid argument. + /// > + /// > Nothing is published: the caller's other devices see the change on + /// > their next GetFeaturedGroups. + /// + /// - Parameters: + /// - message: request message to send. + /// - metadata: Additional metadata to send, defaults to empty. + /// - options: Options to apply to this RPC, defaults to `.defaults`. + /// - handleResponse: A closure which handles the response, the result of which is + /// returned to the caller. Returning from the closure will cancel the RPC if it + /// hasn't already finished. + /// - Returns: The result of `handleResponse`. + public func setFeaturedGroups( + _ message: Flipcash_Chat_V1_SetFeaturedGroupsRequest, + metadata: GRPCCore.Metadata = [:], + options: GRPCCore.CallOptions = .defaults, + onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse) async throws -> Result = { response in + try response.message + } + ) async throws -> Result where Result: Sendable { + let request = GRPCCore.ClientRequest( + message: message, + metadata: metadata + ) + return try await self.setFeaturedGroups( + request: request, + options: options, + onResponse: handleResponse + ) + } + + /// Call the "GetFeaturedGroups" method. + /// + /// > Source IDL Documentation: + /// > + /// > GetFeaturedGroups returns a user's featured groups (see + /// > SetFeaturedGroups), in the order the user set them. + /// > + /// > Each group is a public group (see SetFeaturedGroups), returned as its + /// > record as a list view shows it: chat_id, type, title, description, + /// > profile_picture, roster_summary, rules, creator and last_activity. Nothing about the viewer's place in the + /// > group is set (members, is_hidden, viewer_state, in_lobby), nor its + /// > messaging state (last_message, latest_event_sequence), nor its + /// > cover_picture: a client opening a group fetches the rest with GetChat. + /// > + /// > The list is public, like the user's profile, and the same for every + /// > viewer. Auth is optional; when set it must be valid, but it changes + /// > nothing about what is returned. A group that no longer exists is left + /// > out. + /// > + /// > The user is identified by username, the handle a profile is opened by, + /// > so a client can fetch a profile (see profile.v1.Profile.GetProfile) and + /// > its featured groups at once. + /// + /// - Parameters: + /// - message: request message to send. + /// - metadata: Additional metadata to send, defaults to empty. + /// - options: Options to apply to this RPC, defaults to `.defaults`. + /// - handleResponse: A closure which handles the response, the result of which is + /// returned to the caller. Returning from the closure will cancel the RPC if it + /// hasn't already finished. + /// - Returns: The result of `handleResponse`. + public func getFeaturedGroups( + _ message: Flipcash_Chat_V1_GetFeaturedGroupsRequest, + metadata: GRPCCore.Metadata = [:], + options: GRPCCore.CallOptions = .defaults, + onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse) async throws -> Result = { response in + try response.message + } + ) async throws -> Result where Result: Sendable { + let request = GRPCCore.ClientRequest( + message: message, + metadata: metadata + ) + return try await self.getFeaturedGroups( + request: request, + options: options, + onResponse: handleResponse + ) + } } \ No newline at end of file diff --git a/Sources/Flipcash2ClientProtocol/chat_v1_chat_service.pb.swift b/Sources/Flipcash2ClientProtocol/chat_v1_chat_service.pb.swift index 078cc52..7ec54e0 100644 --- a/Sources/Flipcash2ClientProtocol/chat_v1_chat_service.pb.swift +++ b/Sources/Flipcash2ClientProtocol/chat_v1_chat_service.pb.swift @@ -37,11 +37,12 @@ public struct Flipcash_Chat_V1_GetChatRequest: Sendable { /// What the client intends to render of the chat's messaging state — its /// last_message and latest_event_sequence — and so whether they may be /// returned redacted (see messaging.v1.ViewMode). A group's record (title, - /// description, picture, rules, roster summary) is returned to every - /// registered user whatever the mode; the mode decides only the messaging - /// state, which is withheld from a viewer who may not read the chat under - /// it. Unset (FULL) is the pre-redaction contract: messaging state for a - /// viewer who may read the chat in full, the bare record for anyone else. + /// description, profile picture, cover picture, rules, roster summary) is + /// returned to every registered user whatever the mode; the mode decides + /// only the messaging state, which is withheld from a viewer who may not + /// read the chat under it. Unset (FULL) is the pre-redaction contract: + /// messaging state for a viewer who may read the chat in full, the bare + /// record for anyone else. /// /// Must be REDACTED when auth is unset; any other mode is DENIED. public var viewMode: Flipcash_Messaging_V1_ViewMode = .full @@ -502,6 +503,100 @@ public struct Flipcash_Chat_V1_GetRosterResponse: Sendable { fileprivate var _pagingToken: Flipcash_Common_V1_PagingToken? = nil } +public struct Flipcash_Chat_V1_SampleChattersRequest: Sendable { + // SwiftProtobuf.Message conformance is added in an extension below. See the + // `Message` and `Message+*Additions` files in the SwiftProtobuf library for + // methods supported on all messages. + + public var chatID: Flipcash_Common_V1_ChatId { + get {return _chatID ?? Flipcash_Common_V1_ChatId()} + set {_chatID = newValue} + } + /// Returns true if `chatID` has been explicitly set. + public var hasChatID: Bool {return self._chatID != nil} + /// Clears the value of `chatID`. Subsequent reads from it will return its default value. + public mutating func clearChatID() {self._chatID = nil} + + /// Optional. When set it must be valid, but the sample is the same with + /// or without it (see Chat.SampleChatters). + public var auth: Flipcash_Common_V1_Auth { + get {return _auth ?? Flipcash_Common_V1_Auth()} + set {_auth = newValue} + } + /// Returns true if `auth` has been explicitly set. + public var hasAuth: Bool {return self._auth != nil} + /// Clears the value of `auth`. Subsequent reads from it will return its default value. + public mutating func clearAuth() {self._auth = nil} + + public var unknownFields = SwiftProtobuf.UnknownStorage() + + public init() {} + + fileprivate var _chatID: Flipcash_Common_V1_ChatId? = nil + fileprivate var _auth: Flipcash_Common_V1_Auth? = nil +} + +public struct Flipcash_Chat_V1_SampleChattersResponse: Sendable { + // SwiftProtobuf.Message conformance is added in an extension below. See the + // `Message` and `Message+*Additions` files in the SwiftProtobuf library for + // methods supported on all messages. + + public var result: Flipcash_Chat_V1_SampleChattersResponse.Result = .ok + + /// The sample, every one a member as of the read: the creator first, when + /// they are a member, then the most recent senders, most recent first. + /// Set when result is OK. + public var chatters: [Flipcash_Chat_V1_SampledChatter] = [] + + /// Whether the group may have more members who have sent recently than + /// the sample holds, for a client to show that there are others. It is + /// true when the server knows of more, and also when it stopped looking + /// before it could tell. Set when result is OK. + public var hasMore_p: Bool = false + + public var unknownFields = SwiftProtobuf.UnknownStorage() + + public enum Result: SwiftProtobuf.Enum, Swift.CaseIterable { + public typealias RawValue = Int + case ok // = 0 + case denied // = 1 + case notFound // = 2 + case UNRECOGNIZED(Int) + + public init() { + self = .ok + } + + public init?(rawValue: Int) { + switch rawValue { + case 0: self = .ok + case 1: self = .denied + case 2: self = .notFound + default: self = .UNRECOGNIZED(rawValue) + } + } + + public var rawValue: Int { + switch self { + case .ok: return 0 + case .denied: return 1 + case .notFound: return 2 + case .UNRECOGNIZED(let i): return i + } + } + + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Flipcash_Chat_V1_SampleChattersResponse.Result] = [ + .ok, + .denied, + .notFound, + ] + + } + + public init() {} +} + public struct Flipcash_Chat_V1_GetMentionSuggestionsRequest: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for @@ -655,16 +750,16 @@ public struct Flipcash_Chat_V1_StartChatRequest: Sendable { /// Title for the chat. public var title: String = String() - /// The blob holding the ORIGINAL picture the caller uploaded. Optional. - /// If set, it must be owned by the caller and READY. - public var picture: Flipcash_Blob_V1_BlobId { - get {return _picture ?? Flipcash_Blob_V1_BlobId()} - set {_picture = newValue} + /// The blob holding the ORIGINAL profile picture the caller uploaded. + /// Optional. If set, it must be owned by the caller and READY. + public var profilePicture: Flipcash_Blob_V1_BlobId { + get {return _profilePicture ?? Flipcash_Blob_V1_BlobId()} + set {_profilePicture = newValue} } - /// Returns true if `picture` has been explicitly set. - public var hasPicture: Bool {return self._picture != nil} - /// Clears the value of `picture`. Subsequent reads from it will return its default value. - public mutating func clearPicture() {self._picture = nil} + /// Returns true if `profilePicture` has been explicitly set. + public var hasProfilePicture: Bool {return self._profilePicture != nil} + /// Clears the value of `profilePicture`. Subsequent reads from it will return its default value. + public mutating func clearProfilePicture() {self._profilePicture = nil} /// Rules governing participation in the chat. Optional; if not set, the /// chat has no participation requirements. Caller must satisfy the rules @@ -682,12 +777,24 @@ public struct Flipcash_Chat_V1_StartChatRequest: Sendable { /// the title. public var description_p: String = String() + /// The blob holding the ORIGINAL cover picture the caller uploaded. + /// Optional. If set, it must be owned by the caller and READY. + public var coverPicture: Flipcash_Blob_V1_BlobId { + get {return _coverPicture ?? Flipcash_Blob_V1_BlobId()} + set {_coverPicture = newValue} + } + /// Returns true if `coverPicture` has been explicitly set. + public var hasCoverPicture: Bool {return self._coverPicture != nil} + /// Clears the value of `coverPicture`. Subsequent reads from it will return its default value. + public mutating func clearCoverPicture() {self._coverPicture = nil} + public var unknownFields = SwiftProtobuf.UnknownStorage() public init() {} - fileprivate var _picture: Flipcash_Blob_V1_BlobId? = nil + fileprivate var _profilePicture: Flipcash_Blob_V1_BlobId? = nil fileprivate var _rules: Flipcash_Chat_V1_Rules? = nil + fileprivate var _coverPicture: Flipcash_Blob_V1_BlobId? = nil } /// Parameters for creating a private group chat (see Metadata.is_private): @@ -719,26 +826,38 @@ public struct Flipcash_Chat_V1_StartChatRequest: Sendable { /// Title for the chat. public var title: String = String() - /// The blob holding the ORIGINAL picture the caller uploaded. Optional. - /// If set, it must be owned by the caller and READY. - public var picture: Flipcash_Blob_V1_BlobId { - get {return _picture ?? Flipcash_Blob_V1_BlobId()} - set {_picture = newValue} + /// The blob holding the ORIGINAL profile picture the caller uploaded. + /// Optional. If set, it must be owned by the caller and READY. + public var profilePicture: Flipcash_Blob_V1_BlobId { + get {return _profilePicture ?? Flipcash_Blob_V1_BlobId()} + set {_profilePicture = newValue} } - /// Returns true if `picture` has been explicitly set. - public var hasPicture: Bool {return self._picture != nil} - /// Clears the value of `picture`. Subsequent reads from it will return its default value. - public mutating func clearPicture() {self._picture = nil} + /// Returns true if `profilePicture` has been explicitly set. + public var hasProfilePicture: Bool {return self._profilePicture != nil} + /// Clears the value of `profilePicture`. Subsequent reads from it will return its default value. + public mutating func clearProfilePicture() {self._profilePicture = nil} /// Description for the chat. Optional; empty sets none. Moderated like /// the title. public var description_p: String = String() + /// The blob holding the ORIGINAL cover picture the caller uploaded. + /// Optional. If set, it must be owned by the caller and READY. + public var coverPicture: Flipcash_Blob_V1_BlobId { + get {return _coverPicture ?? Flipcash_Blob_V1_BlobId()} + set {_coverPicture = newValue} + } + /// Returns true if `coverPicture` has been explicitly set. + public var hasCoverPicture: Bool {return self._coverPicture != nil} + /// Clears the value of `coverPicture`. Subsequent reads from it will return its default value. + public mutating func clearCoverPicture() {self._coverPicture = nil} + public var unknownFields = SwiftProtobuf.UnknownStorage() public init() {} - fileprivate var _picture: Flipcash_Blob_V1_BlobId? = nil + fileprivate var _profilePicture: Flipcash_Blob_V1_BlobId? = nil + fileprivate var _coverPicture: Flipcash_Blob_V1_BlobId? = nil } public init() {} @@ -755,8 +874,8 @@ public struct Flipcash_Chat_V1_StartChatResponse: Sendable { public var result: Flipcash_Chat_V1_StartChatResponse.Result = .ok /// The metadata for the newly created chat, including the server-generated - /// chat_id and any picture renditions the server derived. Set only when - /// result == OK. + /// chat_id and any profile picture or cover picture renditions the server + /// derived. Set only when result == OK. public var chat: Flipcash_Chat_V1_Metadata { get {return _chat ?? Flipcash_Chat_V1_Metadata()} set {_chat = newValue} @@ -778,10 +897,11 @@ public struct Flipcash_Chat_V1_StartChatResponse: Sendable { case ok // = 0 case denied // = 1 case titleModerated // = 2 - case pictureBlobNotAccepted // = 3 + case profilePictureBlobNotAccepted // = 3 case invalidRules // = 4 case rulesNotSatisfied // = 5 case descriptionModerated // = 6 + case coverPictureBlobNotAccepted // = 7 case UNRECOGNIZED(Int) public init() { @@ -793,10 +913,11 @@ public struct Flipcash_Chat_V1_StartChatResponse: Sendable { case 0: self = .ok case 1: self = .denied case 2: self = .titleModerated - case 3: self = .pictureBlobNotAccepted + case 3: self = .profilePictureBlobNotAccepted case 4: self = .invalidRules case 5: self = .rulesNotSatisfied case 6: self = .descriptionModerated + case 7: self = .coverPictureBlobNotAccepted default: self = .UNRECOGNIZED(rawValue) } } @@ -806,10 +927,11 @@ public struct Flipcash_Chat_V1_StartChatResponse: Sendable { case .ok: return 0 case .denied: return 1 case .titleModerated: return 2 - case .pictureBlobNotAccepted: return 3 + case .profilePictureBlobNotAccepted: return 3 case .invalidRules: return 4 case .rulesNotSatisfied: return 5 case .descriptionModerated: return 6 + case .coverPictureBlobNotAccepted: return 7 case .UNRECOGNIZED(let i): return i } } @@ -819,10 +941,11 @@ public struct Flipcash_Chat_V1_StartChatResponse: Sendable { .ok, .denied, .titleModerated, - .pictureBlobNotAccepted, + .profilePictureBlobNotAccepted, .invalidRules, .rulesNotSatisfied, .descriptionModerated, + .coverPictureBlobNotAccepted, ] } @@ -1035,15 +1158,15 @@ public struct Flipcash_Chat_V1_EditChatRequest: Sendable { /// Clears the value of `title`. Subsequent reads from it will return its default value. public mutating func clearTitle() {self._title = nil} - /// The new picture. Left unchanged when unset. - public var picture: Flipcash_Chat_V1_EditChatRequest.Picture { - get {return _picture ?? Flipcash_Chat_V1_EditChatRequest.Picture()} - set {_picture = newValue} + /// The new profile picture. Left unchanged when unset. + public var profilePicture: Flipcash_Chat_V1_EditChatRequest.ProfilePicture { + get {return _profilePicture ?? Flipcash_Chat_V1_EditChatRequest.ProfilePicture()} + set {_profilePicture = newValue} } - /// Returns true if `picture` has been explicitly set. - public var hasPicture: Bool {return self._picture != nil} - /// Clears the value of `picture`. Subsequent reads from it will return its default value. - public mutating func clearPicture() {self._picture = nil} + /// Returns true if `profilePicture` has been explicitly set. + public var hasProfilePicture: Bool {return self._profilePicture != nil} + /// Clears the value of `profilePicture`. Subsequent reads from it will return its default value. + public mutating func clearProfilePicture() {self._profilePicture = nil} /// The new description. Left unchanged when unset. public var description_p: Flipcash_Chat_V1_EditChatRequest.Description { @@ -1055,6 +1178,16 @@ public struct Flipcash_Chat_V1_EditChatRequest: Sendable { /// Clears the value of `description_p`. Subsequent reads from it will return its default value. public mutating func clearDescription_p() {self._description_p = nil} + /// The new cover picture. Left unchanged when unset. + public var coverPicture: Flipcash_Chat_V1_EditChatRequest.CoverPicture { + get {return _coverPicture ?? Flipcash_Chat_V1_EditChatRequest.CoverPicture()} + set {_coverPicture = newValue} + } + /// Returns true if `coverPicture` has been explicitly set. + public var hasCoverPicture: Bool {return self._coverPicture != nil} + /// Clears the value of `coverPicture`. Subsequent reads from it will return its default value. + public mutating func clearCoverPicture() {self._coverPicture = nil} + public var auth: Flipcash_Common_V1_Auth { get {return _auth ?? Flipcash_Common_V1_Auth()} set {_auth = newValue} @@ -1078,14 +1211,14 @@ public struct Flipcash_Chat_V1_EditChatRequest: Sendable { public init() {} } - public struct Picture: Sendable { + public struct ProfilePicture: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. - /// The blob holding the ORIGINAL picture the caller uploaded. It must be - /// owned by the caller and READY; the server derives the remaining - /// renditions from it. + /// The blob holding the ORIGINAL profile picture the caller uploaded. It + /// must be owned by the caller and READY; the server derives the + /// remaining renditions from it. public var blobID: Flipcash_Blob_V1_BlobId { get {return _blobID ?? Flipcash_Blob_V1_BlobId()} set {_blobID = newValue} @@ -1115,12 +1248,37 @@ public struct Flipcash_Chat_V1_EditChatRequest: Sendable { public init() {} } + public struct CoverPicture: Sendable { + // SwiftProtobuf.Message conformance is added in an extension below. See the + // `Message` and `Message+*Additions` files in the SwiftProtobuf library for + // methods supported on all messages. + + /// The blob holding the ORIGINAL cover picture the caller uploaded. It + /// must be owned by the caller and READY; the server derives the + /// remaining renditions from it. + public var blobID: Flipcash_Blob_V1_BlobId { + get {return _blobID ?? Flipcash_Blob_V1_BlobId()} + set {_blobID = newValue} + } + /// Returns true if `blobID` has been explicitly set. + public var hasBlobID: Bool {return self._blobID != nil} + /// Clears the value of `blobID`. Subsequent reads from it will return its default value. + public mutating func clearBlobID() {self._blobID = nil} + + public var unknownFields = SwiftProtobuf.UnknownStorage() + + public init() {} + + fileprivate var _blobID: Flipcash_Blob_V1_BlobId? = nil + } + public init() {} fileprivate var _chatID: Flipcash_Common_V1_ChatId? = nil fileprivate var _title: Flipcash_Chat_V1_EditChatRequest.Title? = nil - fileprivate var _picture: Flipcash_Chat_V1_EditChatRequest.Picture? = nil + fileprivate var _profilePicture: Flipcash_Chat_V1_EditChatRequest.ProfilePicture? = nil fileprivate var _description_p: Flipcash_Chat_V1_EditChatRequest.Description? = nil + fileprivate var _coverPicture: Flipcash_Chat_V1_EditChatRequest.CoverPicture? = nil fileprivate var _auth: Flipcash_Common_V1_Auth? = nil } @@ -1132,8 +1290,8 @@ public struct Flipcash_Chat_V1_EditChatResponse: Sendable { public var result: Flipcash_Chat_V1_EditChatResponse.Result = .ok /// The metadata for the chat after the edit, as seen by the caller, - /// including any picture renditions the server derived. Set only when - /// result == OK. + /// including any profile picture or cover picture renditions the server + /// derived. Set only when result == OK. public var chat: Flipcash_Chat_V1_Metadata { get {return _chat ?? Flipcash_Chat_V1_Metadata()} set {_chat = newValue} @@ -1156,8 +1314,9 @@ public struct Flipcash_Chat_V1_EditChatResponse: Sendable { case denied // = 1 case notFound // = 2 case titleModerated // = 3 - case pictureBlobNotAccepted // = 4 - case descriptionModerated // = 5 + case profilePictureBlobNotAccepted // = 4 + case coverPictureBlobNotAccepted // = 5 + case descriptionModerated // = 6 case UNRECOGNIZED(Int) public init() { @@ -1170,8 +1329,9 @@ public struct Flipcash_Chat_V1_EditChatResponse: Sendable { case 1: self = .denied case 2: self = .notFound case 3: self = .titleModerated - case 4: self = .pictureBlobNotAccepted - case 5: self = .descriptionModerated + case 4: self = .profilePictureBlobNotAccepted + case 5: self = .coverPictureBlobNotAccepted + case 6: self = .descriptionModerated default: self = .UNRECOGNIZED(rawValue) } } @@ -1182,8 +1342,9 @@ public struct Flipcash_Chat_V1_EditChatResponse: Sendable { case .denied: return 1 case .notFound: return 2 case .titleModerated: return 3 - case .pictureBlobNotAccepted: return 4 - case .descriptionModerated: return 5 + case .profilePictureBlobNotAccepted: return 4 + case .coverPictureBlobNotAccepted: return 5 + case .descriptionModerated: return 6 case .UNRECOGNIZED(let i): return i } } @@ -1194,7 +1355,8 @@ public struct Flipcash_Chat_V1_EditChatResponse: Sendable { .denied, .notFound, .titleModerated, - .pictureBlobNotAccepted, + .profilePictureBlobNotAccepted, + .coverPictureBlobNotAccepted, .descriptionModerated, ] @@ -2149,6 +2311,184 @@ public struct Flipcash_Chat_V1_GetKeyEnvelopeResponse: Sendable { fileprivate var _wrappedBy: Flipcash_Common_V1_UserId? = nil } +public struct Flipcash_Chat_V1_SetFeaturedGroupsRequest: Sendable { + // SwiftProtobuf.Message conformance is added in an extension below. See the + // `Message` and `Message+*Additions` files in the SwiftProtobuf library for + // methods supported on all messages. + + /// The groups to feature, in the order to show them. Every ID must name a + /// public group chat, and none may repeat. Empty clears the featured + /// groups. + public var chatIds: [Flipcash_Common_V1_ChatId] = [] + + public var auth: Flipcash_Common_V1_Auth { + get {return _auth ?? Flipcash_Common_V1_Auth()} + set {_auth = newValue} + } + /// Returns true if `auth` has been explicitly set. + public var hasAuth: Bool {return self._auth != nil} + /// Clears the value of `auth`. Subsequent reads from it will return its default value. + public mutating func clearAuth() {self._auth = nil} + + public var unknownFields = SwiftProtobuf.UnknownStorage() + + public init() {} + + fileprivate var _auth: Flipcash_Common_V1_Auth? = nil +} + +public struct Flipcash_Chat_V1_SetFeaturedGroupsResponse: Sendable { + // SwiftProtobuf.Message conformance is added in an extension below. See the + // `Message` and `Message+*Additions` files in the SwiftProtobuf library for + // methods supported on all messages. + + public var result: Flipcash_Chat_V1_SetFeaturedGroupsResponse.Result = .ok + + /// The caller's featured groups after the write, as GetFeaturedGroups + /// returns them. Set only when result == OK. + public var featuredGroups: [Flipcash_Chat_V1_Metadata] = [] + + public var unknownFields = SwiftProtobuf.UnknownStorage() + + public enum Result: SwiftProtobuf.Enum, Swift.CaseIterable { + public typealias RawValue = Int + case ok // = 0 + + /// A group in the request is private; nothing was written + case denied // = 1 + + /// A group in the request does not exist; nothing was written + case notFound // = 2 + case UNRECOGNIZED(Int) + + public init() { + self = .ok + } + + public init?(rawValue: Int) { + switch rawValue { + case 0: self = .ok + case 1: self = .denied + case 2: self = .notFound + default: self = .UNRECOGNIZED(rawValue) + } + } + + public var rawValue: Int { + switch self { + case .ok: return 0 + case .denied: return 1 + case .notFound: return 2 + case .UNRECOGNIZED(let i): return i + } + } + + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Flipcash_Chat_V1_SetFeaturedGroupsResponse.Result] = [ + .ok, + .denied, + .notFound, + ] + + } + + public init() {} +} + +public struct Flipcash_Chat_V1_GetFeaturedGroupsRequest: Sendable { + // SwiftProtobuf.Message conformance is added in an extension below. See the + // `Message` and `Message+*Additions` files in the SwiftProtobuf library for + // methods supported on all messages. + + /// The user whose featured groups are being fetched. Only a username is + /// supported for now; the oneof leaves room for other identifiers. + public var identifier: Flipcash_Chat_V1_GetFeaturedGroupsRequest.OneOf_Identifier? = nil + + public var username: Flipcash_Common_V1_Username { + get { + if case .username(let v)? = identifier {return v} + return Flipcash_Common_V1_Username() + } + set {identifier = .username(newValue)} + } + + /// Optional. When set it must be valid, but the list is the same with or + /// without it (see Chat.GetFeaturedGroups). + public var auth: Flipcash_Common_V1_Auth { + get {return _auth ?? Flipcash_Common_V1_Auth()} + set {_auth = newValue} + } + /// Returns true if `auth` has been explicitly set. + public var hasAuth: Bool {return self._auth != nil} + /// Clears the value of `auth`. Subsequent reads from it will return its default value. + public mutating func clearAuth() {self._auth = nil} + + public var unknownFields = SwiftProtobuf.UnknownStorage() + + /// The user whose featured groups are being fetched. Only a username is + /// supported for now; the oneof leaves room for other identifiers. + public enum OneOf_Identifier: Equatable, Sendable { + case username(Flipcash_Common_V1_Username) + + } + + public init() {} + + fileprivate var _auth: Flipcash_Common_V1_Auth? = nil +} + +public struct Flipcash_Chat_V1_GetFeaturedGroupsResponse: Sendable { + // SwiftProtobuf.Message conformance is added in an extension below. See the + // `Message` and `Message+*Additions` files in the SwiftProtobuf library for + // methods supported on all messages. + + public var result: Flipcash_Chat_V1_GetFeaturedGroupsResponse.Result = .ok + + /// The user's featured groups, in their order. Empty when they feature + /// none. Set only when result == OK. + public var featuredGroups: [Flipcash_Chat_V1_Metadata] = [] + + public var unknownFields = SwiftProtobuf.UnknownStorage() + + public enum Result: SwiftProtobuf.Enum, Swift.CaseIterable { + public typealias RawValue = Int + case ok // = 0 + + /// No user holds the username + case notFound // = 1 + case UNRECOGNIZED(Int) + + public init() { + self = .ok + } + + public init?(rawValue: Int) { + switch rawValue { + case 0: self = .ok + case 1: self = .notFound + default: self = .UNRECOGNIZED(rawValue) + } + } + + public var rawValue: Int { + switch self { + case .ok: return 0 + case .notFound: return 1 + case .UNRECOGNIZED(let i): return i + } + } + + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Flipcash_Chat_V1_GetFeaturedGroupsResponse.Result] = [ + .ok, + .notFound, + ] + + } + + public init() {} +} + // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "flipcash.chat.v1" @@ -2531,6 +2871,89 @@ extension Flipcash_Chat_V1_GetRosterResponse.Result: SwiftProtobuf._ProtoNamePro public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{2}\0OK\0\u{1}DENIED\0\u{1}NOT_FOUND\0") } +extension Flipcash_Chat_V1_SampleChattersRequest: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".SampleChattersRequest" + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{3}chat_id\0\u{2}\u{9}auth\0") + + public mutating func decodeMessage(decoder: inout D) throws { + while let fieldNumber = try decoder.nextFieldNumber() { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every case branch when no optimizations are + // enabled. https://github.com/apple/swift-protobuf/issues/1034 + switch fieldNumber { + case 1: try { try decoder.decodeSingularMessageField(value: &self._chatID) }() + case 10: try { try decoder.decodeSingularMessageField(value: &self._auth) }() + default: break + } + } + } + + public func traverse(visitor: inout V) throws { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every if/case branch local when no optimizations + // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and + // https://github.com/apple/swift-protobuf/issues/1182 + try { if let v = self._chatID { + try visitor.visitSingularMessageField(value: v, fieldNumber: 1) + } }() + try { if let v = self._auth { + try visitor.visitSingularMessageField(value: v, fieldNumber: 10) + } }() + try unknownFields.traverse(visitor: &visitor) + } + + public static func ==(lhs: Flipcash_Chat_V1_SampleChattersRequest, rhs: Flipcash_Chat_V1_SampleChattersRequest) -> Bool { + if lhs._chatID != rhs._chatID {return false} + if lhs._auth != rhs._auth {return false} + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} + +extension Flipcash_Chat_V1_SampleChattersResponse: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".SampleChattersResponse" + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}result\0\u{1}chatters\0\u{3}has_more\0") + + public mutating func decodeMessage(decoder: inout D) throws { + while let fieldNumber = try decoder.nextFieldNumber() { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every case branch when no optimizations are + // enabled. https://github.com/apple/swift-protobuf/issues/1034 + switch fieldNumber { + case 1: try { try decoder.decodeSingularEnumField(value: &self.result) }() + case 2: try { try decoder.decodeRepeatedMessageField(value: &self.chatters) }() + case 3: try { try decoder.decodeSingularBoolField(value: &self.hasMore_p) }() + default: break + } + } + } + + public func traverse(visitor: inout V) throws { + if self.result != .ok { + try visitor.visitSingularEnumField(value: self.result, fieldNumber: 1) + } + if !self.chatters.isEmpty { + try visitor.visitRepeatedMessageField(value: self.chatters, fieldNumber: 2) + } + if self.hasMore_p != false { + try visitor.visitSingularBoolField(value: self.hasMore_p, fieldNumber: 3) + } + try unknownFields.traverse(visitor: &visitor) + } + + public static func ==(lhs: Flipcash_Chat_V1_SampleChattersResponse, rhs: Flipcash_Chat_V1_SampleChattersResponse) -> Bool { + if lhs.result != rhs.result {return false} + if lhs.chatters != rhs.chatters {return false} + if lhs.hasMore_p != rhs.hasMore_p {return false} + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} + +extension Flipcash_Chat_V1_SampleChattersResponse.Result: SwiftProtobuf._ProtoNameProviding { + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{2}\0OK\0\u{1}DENIED\0\u{1}NOT_FOUND\0") +} + extension Flipcash_Chat_V1_GetMentionSuggestionsRequest: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".GetMentionSuggestionsRequest" public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{3}chat_id\0\u{2}\u{9}auth\0") @@ -2688,7 +3111,7 @@ extension Flipcash_Chat_V1_StartChatRequest: SwiftProtobuf.Message, SwiftProtobu extension Flipcash_Chat_V1_StartChatRequest.PublicGroupChatParameters: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = Flipcash_Chat_V1_StartChatRequest.protoMessageName + ".PublicGroupChatParameters" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}title\0\u{1}picture\0\u{1}rules\0\u{1}description\0") + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}title\0\u{3}profile_picture\0\u{1}rules\0\u{1}description\0\u{3}cover_picture\0") public mutating func decodeMessage(decoder: inout D) throws { while let fieldNumber = try decoder.nextFieldNumber() { @@ -2697,9 +3120,10 @@ extension Flipcash_Chat_V1_StartChatRequest.PublicGroupChatParameters: SwiftProt // enabled. https://github.com/apple/swift-protobuf/issues/1034 switch fieldNumber { case 1: try { try decoder.decodeSingularStringField(value: &self.title) }() - case 2: try { try decoder.decodeSingularMessageField(value: &self._picture) }() + case 2: try { try decoder.decodeSingularMessageField(value: &self._profilePicture) }() case 3: try { try decoder.decodeSingularMessageField(value: &self._rules) }() case 4: try { try decoder.decodeSingularStringField(value: &self.description_p) }() + case 5: try { try decoder.decodeSingularMessageField(value: &self._coverPicture) }() default: break } } @@ -2713,7 +3137,7 @@ extension Flipcash_Chat_V1_StartChatRequest.PublicGroupChatParameters: SwiftProt if !self.title.isEmpty { try visitor.visitSingularStringField(value: self.title, fieldNumber: 1) } - try { if let v = self._picture { + try { if let v = self._profilePicture { try visitor.visitSingularMessageField(value: v, fieldNumber: 2) } }() try { if let v = self._rules { @@ -2722,14 +3146,18 @@ extension Flipcash_Chat_V1_StartChatRequest.PublicGroupChatParameters: SwiftProt if !self.description_p.isEmpty { try visitor.visitSingularStringField(value: self.description_p, fieldNumber: 4) } + try { if let v = self._coverPicture { + try visitor.visitSingularMessageField(value: v, fieldNumber: 5) + } }() try unknownFields.traverse(visitor: &visitor) } public static func ==(lhs: Flipcash_Chat_V1_StartChatRequest.PublicGroupChatParameters, rhs: Flipcash_Chat_V1_StartChatRequest.PublicGroupChatParameters) -> Bool { if lhs.title != rhs.title {return false} - if lhs._picture != rhs._picture {return false} + if lhs._profilePicture != rhs._profilePicture {return false} if lhs._rules != rhs._rules {return false} if lhs.description_p != rhs.description_p {return false} + if lhs._coverPicture != rhs._coverPicture {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true } @@ -2737,7 +3165,7 @@ extension Flipcash_Chat_V1_StartChatRequest.PublicGroupChatParameters: SwiftProt extension Flipcash_Chat_V1_StartChatRequest.PrivateGroupChatParameters: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = Flipcash_Chat_V1_StartChatRequest.protoMessageName + ".PrivateGroupChatParameters" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}title\0\u{1}picture\0\u{1}description\0") + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}title\0\u{3}profile_picture\0\u{1}description\0\u{3}cover_picture\0") public mutating func decodeMessage(decoder: inout D) throws { while let fieldNumber = try decoder.nextFieldNumber() { @@ -2746,8 +3174,9 @@ extension Flipcash_Chat_V1_StartChatRequest.PrivateGroupChatParameters: SwiftPro // enabled. https://github.com/apple/swift-protobuf/issues/1034 switch fieldNumber { case 1: try { try decoder.decodeSingularStringField(value: &self.title) }() - case 2: try { try decoder.decodeSingularMessageField(value: &self._picture) }() + case 2: try { try decoder.decodeSingularMessageField(value: &self._profilePicture) }() case 3: try { try decoder.decodeSingularStringField(value: &self.description_p) }() + case 4: try { try decoder.decodeSingularMessageField(value: &self._coverPicture) }() default: break } } @@ -2761,19 +3190,23 @@ extension Flipcash_Chat_V1_StartChatRequest.PrivateGroupChatParameters: SwiftPro if !self.title.isEmpty { try visitor.visitSingularStringField(value: self.title, fieldNumber: 1) } - try { if let v = self._picture { + try { if let v = self._profilePicture { try visitor.visitSingularMessageField(value: v, fieldNumber: 2) } }() if !self.description_p.isEmpty { try visitor.visitSingularStringField(value: self.description_p, fieldNumber: 3) } + try { if let v = self._coverPicture { + try visitor.visitSingularMessageField(value: v, fieldNumber: 4) + } }() try unknownFields.traverse(visitor: &visitor) } public static func ==(lhs: Flipcash_Chat_V1_StartChatRequest.PrivateGroupChatParameters, rhs: Flipcash_Chat_V1_StartChatRequest.PrivateGroupChatParameters) -> Bool { if lhs.title != rhs.title {return false} - if lhs._picture != rhs._picture {return false} + if lhs._profilePicture != rhs._profilePicture {return false} if lhs.description_p != rhs.description_p {return false} + if lhs._coverPicture != rhs._coverPicture {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true } @@ -2824,7 +3257,7 @@ extension Flipcash_Chat_V1_StartChatResponse: SwiftProtobuf.Message, SwiftProtob } extension Flipcash_Chat_V1_StartChatResponse.Result: SwiftProtobuf._ProtoNameProviding { - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{2}\0OK\0\u{1}DENIED\0\u{1}TITLE_MODERATED\0\u{1}PICTURE_BLOB_NOT_ACCEPTED\0\u{1}INVALID_RULES\0\u{1}RULES_NOT_SATISFIED\0\u{1}DESCRIPTION_MODERATED\0") + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{2}\0OK\0\u{1}DENIED\0\u{1}TITLE_MODERATED\0\u{1}PROFILE_PICTURE_BLOB_NOT_ACCEPTED\0\u{1}INVALID_RULES\0\u{1}RULES_NOT_SATISFIED\0\u{1}DESCRIPTION_MODERATED\0\u{1}COVER_PICTURE_BLOB_NOT_ACCEPTED\0") } extension Flipcash_Chat_V1_JoinChatRequest: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { @@ -2984,7 +3417,7 @@ extension Flipcash_Chat_V1_LeaveChatResponse.Result: SwiftProtobuf._ProtoNamePro extension Flipcash_Chat_V1_EditChatRequest: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".EditChatRequest" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{3}chat_id\0\u{1}title\0\u{1}picture\0\u{1}description\0\u{2}\u{6}auth\0") + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{3}chat_id\0\u{1}title\0\u{3}profile_picture\0\u{1}description\0\u{3}cover_picture\0\u{2}\u{5}auth\0") public mutating func decodeMessage(decoder: inout D) throws { while let fieldNumber = try decoder.nextFieldNumber() { @@ -2994,8 +3427,9 @@ extension Flipcash_Chat_V1_EditChatRequest: SwiftProtobuf.Message, SwiftProtobuf switch fieldNumber { case 1: try { try decoder.decodeSingularMessageField(value: &self._chatID) }() case 2: try { try decoder.decodeSingularMessageField(value: &self._title) }() - case 3: try { try decoder.decodeSingularMessageField(value: &self._picture) }() + case 3: try { try decoder.decodeSingularMessageField(value: &self._profilePicture) }() case 4: try { try decoder.decodeSingularMessageField(value: &self._description_p) }() + case 5: try { try decoder.decodeSingularMessageField(value: &self._coverPicture) }() case 10: try { try decoder.decodeSingularMessageField(value: &self._auth) }() default: break } @@ -3013,12 +3447,15 @@ extension Flipcash_Chat_V1_EditChatRequest: SwiftProtobuf.Message, SwiftProtobuf try { if let v = self._title { try visitor.visitSingularMessageField(value: v, fieldNumber: 2) } }() - try { if let v = self._picture { + try { if let v = self._profilePicture { try visitor.visitSingularMessageField(value: v, fieldNumber: 3) } }() try { if let v = self._description_p { try visitor.visitSingularMessageField(value: v, fieldNumber: 4) } }() + try { if let v = self._coverPicture { + try visitor.visitSingularMessageField(value: v, fieldNumber: 5) + } }() try { if let v = self._auth { try visitor.visitSingularMessageField(value: v, fieldNumber: 10) } }() @@ -3028,8 +3465,9 @@ extension Flipcash_Chat_V1_EditChatRequest: SwiftProtobuf.Message, SwiftProtobuf public static func ==(lhs: Flipcash_Chat_V1_EditChatRequest, rhs: Flipcash_Chat_V1_EditChatRequest) -> Bool { if lhs._chatID != rhs._chatID {return false} if lhs._title != rhs._title {return false} - if lhs._picture != rhs._picture {return false} + if lhs._profilePicture != rhs._profilePicture {return false} if lhs._description_p != rhs._description_p {return false} + if lhs._coverPicture != rhs._coverPicture {return false} if lhs._auth != rhs._auth {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true @@ -3066,8 +3504,8 @@ extension Flipcash_Chat_V1_EditChatRequest.Title: SwiftProtobuf.Message, SwiftPr } } -extension Flipcash_Chat_V1_EditChatRequest.Picture: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - public static let protoMessageName: String = Flipcash_Chat_V1_EditChatRequest.protoMessageName + ".Picture" +extension Flipcash_Chat_V1_EditChatRequest.ProfilePicture: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = Flipcash_Chat_V1_EditChatRequest.protoMessageName + ".ProfilePicture" public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{3}blob_id\0") public mutating func decodeMessage(decoder: inout D) throws { @@ -3093,7 +3531,7 @@ extension Flipcash_Chat_V1_EditChatRequest.Picture: SwiftProtobuf.Message, Swift try unknownFields.traverse(visitor: &visitor) } - public static func ==(lhs: Flipcash_Chat_V1_EditChatRequest.Picture, rhs: Flipcash_Chat_V1_EditChatRequest.Picture) -> Bool { + public static func ==(lhs: Flipcash_Chat_V1_EditChatRequest.ProfilePicture, rhs: Flipcash_Chat_V1_EditChatRequest.ProfilePicture) -> Bool { if lhs._blobID != rhs._blobID {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true @@ -3130,6 +3568,40 @@ extension Flipcash_Chat_V1_EditChatRequest.Description: SwiftProtobuf.Message, S } } +extension Flipcash_Chat_V1_EditChatRequest.CoverPicture: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = Flipcash_Chat_V1_EditChatRequest.protoMessageName + ".CoverPicture" + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{3}blob_id\0") + + public mutating func decodeMessage(decoder: inout D) throws { + while let fieldNumber = try decoder.nextFieldNumber() { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every case branch when no optimizations are + // enabled. https://github.com/apple/swift-protobuf/issues/1034 + switch fieldNumber { + case 1: try { try decoder.decodeSingularMessageField(value: &self._blobID) }() + default: break + } + } + } + + public func traverse(visitor: inout V) throws { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every if/case branch local when no optimizations + // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and + // https://github.com/apple/swift-protobuf/issues/1182 + try { if let v = self._blobID { + try visitor.visitSingularMessageField(value: v, fieldNumber: 1) + } }() + try unknownFields.traverse(visitor: &visitor) + } + + public static func ==(lhs: Flipcash_Chat_V1_EditChatRequest.CoverPicture, rhs: Flipcash_Chat_V1_EditChatRequest.CoverPicture) -> Bool { + if lhs._blobID != rhs._blobID {return false} + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} + extension Flipcash_Chat_V1_EditChatResponse: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".EditChatResponse" public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}result\0\u{1}chat\0\u{3}flagged_category\0") @@ -3175,7 +3647,7 @@ extension Flipcash_Chat_V1_EditChatResponse: SwiftProtobuf.Message, SwiftProtobu } extension Flipcash_Chat_V1_EditChatResponse.Result: SwiftProtobuf._ProtoNameProviding { - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{2}\0OK\0\u{1}DENIED\0\u{1}NOT_FOUND\0\u{1}TITLE_MODERATED\0\u{1}PICTURE_BLOB_NOT_ACCEPTED\0\u{1}DESCRIPTION_MODERATED\0") + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{2}\0OK\0\u{1}DENIED\0\u{1}NOT_FOUND\0\u{1}TITLE_MODERATED\0\u{1}PROFILE_PICTURE_BLOB_NOT_ACCEPTED\0\u{1}COVER_PICTURE_BLOB_NOT_ACCEPTED\0\u{1}DESCRIPTION_MODERATED\0") } extension Flipcash_Chat_V1_MuteChatRequest: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { @@ -3924,3 +4396,171 @@ extension Flipcash_Chat_V1_GetKeyEnvelopeResponse: SwiftProtobuf.Message, SwiftP extension Flipcash_Chat_V1_GetKeyEnvelopeResponse.Result: SwiftProtobuf._ProtoNameProviding { public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{2}\0OK\0\u{1}DENIED\0\u{1}NOT_FOUND\0\u{1}NO_ENVELOPE\0") } + +extension Flipcash_Chat_V1_SetFeaturedGroupsRequest: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".SetFeaturedGroupsRequest" + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{3}chat_ids\0\u{2}\u{9}auth\0") + + public mutating func decodeMessage(decoder: inout D) throws { + while let fieldNumber = try decoder.nextFieldNumber() { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every case branch when no optimizations are + // enabled. https://github.com/apple/swift-protobuf/issues/1034 + switch fieldNumber { + case 1: try { try decoder.decodeRepeatedMessageField(value: &self.chatIds) }() + case 10: try { try decoder.decodeSingularMessageField(value: &self._auth) }() + default: break + } + } + } + + public func traverse(visitor: inout V) throws { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every if/case branch local when no optimizations + // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and + // https://github.com/apple/swift-protobuf/issues/1182 + if !self.chatIds.isEmpty { + try visitor.visitRepeatedMessageField(value: self.chatIds, fieldNumber: 1) + } + try { if let v = self._auth { + try visitor.visitSingularMessageField(value: v, fieldNumber: 10) + } }() + try unknownFields.traverse(visitor: &visitor) + } + + public static func ==(lhs: Flipcash_Chat_V1_SetFeaturedGroupsRequest, rhs: Flipcash_Chat_V1_SetFeaturedGroupsRequest) -> Bool { + if lhs.chatIds != rhs.chatIds {return false} + if lhs._auth != rhs._auth {return false} + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} + +extension Flipcash_Chat_V1_SetFeaturedGroupsResponse: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".SetFeaturedGroupsResponse" + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}result\0\u{3}featured_groups\0") + + public mutating func decodeMessage(decoder: inout D) throws { + while let fieldNumber = try decoder.nextFieldNumber() { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every case branch when no optimizations are + // enabled. https://github.com/apple/swift-protobuf/issues/1034 + switch fieldNumber { + case 1: try { try decoder.decodeSingularEnumField(value: &self.result) }() + case 2: try { try decoder.decodeRepeatedMessageField(value: &self.featuredGroups) }() + default: break + } + } + } + + public func traverse(visitor: inout V) throws { + if self.result != .ok { + try visitor.visitSingularEnumField(value: self.result, fieldNumber: 1) + } + if !self.featuredGroups.isEmpty { + try visitor.visitRepeatedMessageField(value: self.featuredGroups, fieldNumber: 2) + } + try unknownFields.traverse(visitor: &visitor) + } + + public static func ==(lhs: Flipcash_Chat_V1_SetFeaturedGroupsResponse, rhs: Flipcash_Chat_V1_SetFeaturedGroupsResponse) -> Bool { + if lhs.result != rhs.result {return false} + if lhs.featuredGroups != rhs.featuredGroups {return false} + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} + +extension Flipcash_Chat_V1_SetFeaturedGroupsResponse.Result: SwiftProtobuf._ProtoNameProviding { + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{2}\0OK\0\u{1}DENIED\0\u{1}NOT_FOUND\0") +} + +extension Flipcash_Chat_V1_GetFeaturedGroupsRequest: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".GetFeaturedGroupsRequest" + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}username\0\u{2}\u{9}auth\0") + + public mutating func decodeMessage(decoder: inout D) throws { + while let fieldNumber = try decoder.nextFieldNumber() { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every case branch when no optimizations are + // enabled. https://github.com/apple/swift-protobuf/issues/1034 + switch fieldNumber { + case 1: try { + var v: Flipcash_Common_V1_Username? + var hadOneofValue = false + if let current = self.identifier { + hadOneofValue = true + if case .username(let m) = current {v = m} + } + try decoder.decodeSingularMessageField(value: &v) + if let v = v { + if hadOneofValue {try decoder.handleConflictingOneOf()} + self.identifier = .username(v) + } + }() + case 10: try { try decoder.decodeSingularMessageField(value: &self._auth) }() + default: break + } + } + } + + public func traverse(visitor: inout V) throws { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every if/case branch local when no optimizations + // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and + // https://github.com/apple/swift-protobuf/issues/1182 + try { if case .username(let v)? = self.identifier { + try visitor.visitSingularMessageField(value: v, fieldNumber: 1) + } }() + try { if let v = self._auth { + try visitor.visitSingularMessageField(value: v, fieldNumber: 10) + } }() + try unknownFields.traverse(visitor: &visitor) + } + + public static func ==(lhs: Flipcash_Chat_V1_GetFeaturedGroupsRequest, rhs: Flipcash_Chat_V1_GetFeaturedGroupsRequest) -> Bool { + if lhs.identifier != rhs.identifier {return false} + if lhs._auth != rhs._auth {return false} + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} + +extension Flipcash_Chat_V1_GetFeaturedGroupsResponse: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".GetFeaturedGroupsResponse" + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}result\0\u{3}featured_groups\0") + + public mutating func decodeMessage(decoder: inout D) throws { + while let fieldNumber = try decoder.nextFieldNumber() { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every case branch when no optimizations are + // enabled. https://github.com/apple/swift-protobuf/issues/1034 + switch fieldNumber { + case 1: try { try decoder.decodeSingularEnumField(value: &self.result) }() + case 2: try { try decoder.decodeRepeatedMessageField(value: &self.featuredGroups) }() + default: break + } + } + } + + public func traverse(visitor: inout V) throws { + if self.result != .ok { + try visitor.visitSingularEnumField(value: self.result, fieldNumber: 1) + } + if !self.featuredGroups.isEmpty { + try visitor.visitRepeatedMessageField(value: self.featuredGroups, fieldNumber: 2) + } + try unknownFields.traverse(visitor: &visitor) + } + + public static func ==(lhs: Flipcash_Chat_V1_GetFeaturedGroupsResponse, rhs: Flipcash_Chat_V1_GetFeaturedGroupsResponse) -> Bool { + if lhs.result != rhs.result {return false} + if lhs.featuredGroups != rhs.featuredGroups {return false} + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} + +extension Flipcash_Chat_V1_GetFeaturedGroupsResponse.Result: SwiftProtobuf._ProtoNameProviding { + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{2}\0OK\0\u{1}NOT_FOUND\0") +} diff --git a/Sources/Flipcash2ClientProtocol/chat_v1_model.pb.swift b/Sources/Flipcash2ClientProtocol/chat_v1_model.pb.swift index c050f41..22d5891 100644 --- a/Sources/Flipcash2ClientProtocol/chat_v1_model.pb.swift +++ b/Sources/Flipcash2ClientProtocol/chat_v1_model.pb.swift @@ -143,15 +143,22 @@ public struct Flipcash_Chat_V1_Metadata: @unchecked Sendable { set {_uniqueStorage()._title = newValue} } - /// Picture for this chat. Only supported for group chats - public var picture: Flipcash_Blob_V1_Media { - get {return _storage._picture ?? Flipcash_Blob_V1_Media()} - set {_uniqueStorage()._picture = newValue} - } - /// Returns true if `picture` has been explicitly set. - public var hasPicture: Bool {return _storage._picture != nil} - /// Clears the value of `picture`. Subsequent reads from it will return its default value. - public mutating func clearPicture() {_uniqueStorage()._picture = nil} + /// The chat's profile picture — the avatar shown for it in chat lists and + /// headers — as the set of renditions it is stored as. Only supported for + /// group chats. Not to be confused with cover_picture, the banner shown + /// behind the chat's profile view. + /// + /// Set it on creation (see StartChatRequest) or with Chat.EditChat. To + /// fetch its bytes as a non-member, a GetBlobs call must carry a + /// blob.v1.AccessContext whose `chat_profile` scope names this chat. + public var profilePicture: Flipcash_Blob_V1_Media { + get {return _storage._profilePicture ?? Flipcash_Blob_V1_Media()} + set {_uniqueStorage()._profilePicture = newValue} + } + /// Returns true if `profilePicture` has been explicitly set. + public var hasProfilePicture: Bool {return _storage._profilePicture != nil} + /// Clears the value of `profilePicture`. Subsequent reads from it will return its default value. + public mutating func clearProfilePicture() {_uniqueStorage()._profilePicture = nil} /// Chat roster summary public var rosterSummary: Flipcash_Chat_V1_RosterSummary { @@ -231,11 +238,40 @@ public struct Flipcash_Chat_V1_Metadata: @unchecked Sendable { /// see the chat, including in its public view. /// /// Set it on creation (see StartChatRequest) or with Chat.EditChat. + /// + /// Unlike cover_picture, it is carried by the feed RPCs meant for list + /// views (Chat.GetDmChatFeed, Chat.GetGroupChatFeed) too, so a list row + /// may show it, and an empty value there means none is set. public var description_p: String { get {return _storage._description_p} set {_uniqueStorage()._description_p = newValue} } + /// The chat's cover picture — the banner shown behind the chat's profile + /// view — as the set of renditions it is stored as, like + /// profile_picture. Only supported for group chats. Unset when none is + /// set. Part of the group's record, like profile_picture, so it is + /// returned to every viewer who can see the chat, including in its public + /// view. + /// + /// Set it on creation (see StartChatRequest) or with Chat.EditChat. To + /// fetch its bytes as a non-member, a GetBlobs call must carry a + /// blob.v1.AccessContext whose `chat_profile` scope names this chat, + /// exactly as for profile_picture. + /// + /// It may be unset on a chat returned by a feed RPC meant for list views + /// (Chat.GetDmChatFeed, Chat.GetGroupChatFeed), so an unset value there + /// does not mean none is set. Fetch it with Chat.GetChat, and don't let a + /// feed result clear a cover picture the client already holds. + public var coverPicture: Flipcash_Blob_V1_Media { + get {return _storage._coverPicture ?? Flipcash_Blob_V1_Media()} + set {_uniqueStorage()._coverPicture = newValue} + } + /// Returns true if `coverPicture` has been explicitly set. + public var hasCoverPicture: Bool {return _storage._coverPicture != nil} + /// Clears the value of `coverPicture`. Subsequent reads from it will return its default value. + public mutating func clearCoverPicture() {_uniqueStorage()._coverPicture = nil} + /// Whether messages in this chat are end-to-end encrypted (see /// messaging.v1.EncryptedContent). Only supported for DMs (CONTACT_DM or DM); /// always false for group chats. A private group is always end-to-end @@ -555,6 +591,52 @@ public struct Flipcash_Chat_V1_MentionSuggestion: @unchecked Sendable { fileprivate var _storage = _StorageClass.defaultInstance } +/// SampledChatter is one member of a group in a sample of its chatters, as +/// returned by Chat.SampleChatters: a member as of the read. It is not a +/// Member message, carrying no join time or roster version, because a sample +/// is a snapshot replaced whole rather than merged against the roster by +/// version. +public struct Flipcash_Chat_V1_SampledChatter: @unchecked Sendable { + // SwiftProtobuf.Message conformance is added in an extension below. See the + // `Message` and `Message+*Additions` files in the SwiftProtobuf library for + // methods supported on all messages. + + /// The member's public profile. + public var userProfile: Flipcash_Profile_V1_UserProfile { + get {return _storage._userProfile ?? Flipcash_Profile_V1_UserProfile()} + set {_uniqueStorage()._userProfile = newValue} + } + /// Returns true if `userProfile` has been explicitly set. + public var hasUserProfile: Bool {return _storage._userProfile != nil} + /// Clears the value of `userProfile`. Subsequent reads from it will return its default value. + public mutating func clearUserProfile() {_uniqueStorage()._userProfile = nil} + + /// When the member last sent a message in this chat, as the server records + /// it: it may trail their latest message by up to a minute. A client + /// moving new senders to the front compares against it. Unset for a + /// creator who has not sent recently. + public var lastSentAt: SwiftProtobuf.Google_Protobuf_Timestamp { + get {return _storage._lastSentAt ?? SwiftProtobuf.Google_Protobuf_Timestamp()} + set {_uniqueStorage()._lastSentAt = newValue} + } + /// Returns true if `lastSentAt` has been explicitly set. + public var hasLastSentAt: Bool {return _storage._lastSentAt != nil} + /// Clears the value of `lastSentAt`. Subsequent reads from it will return its default value. + public mutating func clearLastSentAt() {_uniqueStorage()._lastSentAt = nil} + + /// Whether the member is the group's creator. + public var isCreator: Bool { + get {return _storage._isCreator} + set {_uniqueStorage()._isCreator = newValue} + } + + public var unknownFields = SwiftProtobuf.UnknownStorage() + + public init() {} + + fileprivate var _storage = _StorageClass.defaultInstance +} + /// RosterSummary describes a chat's roster — its member list — without /// containing it: what a client needs in order to know whether its copy of /// that list is stale, without holding the list. @@ -631,12 +713,12 @@ public struct Flipcash_Chat_V1_MetadataUpdate: Sendable { set {kind = .titleChanged(newValue)} } - public var pictureChanged: Flipcash_Chat_V1_MetadataUpdate.PictureChanged { + public var profilePictureChanged: Flipcash_Chat_V1_MetadataUpdate.ProfilePictureChanged { get { - if case .pictureChanged(let v)? = kind {return v} - return Flipcash_Chat_V1_MetadataUpdate.PictureChanged() + if case .profilePictureChanged(let v)? = kind {return v} + return Flipcash_Chat_V1_MetadataUpdate.ProfilePictureChanged() } - set {kind = .pictureChanged(newValue)} + set {kind = .profilePictureChanged(newValue)} } public var descriptionChanged: Flipcash_Chat_V1_MetadataUpdate.DescriptionChanged { @@ -647,6 +729,14 @@ public struct Flipcash_Chat_V1_MetadataUpdate: Sendable { set {kind = .descriptionChanged(newValue)} } + public var coverPictureChanged: Flipcash_Chat_V1_MetadataUpdate.CoverPictureChanged { + get { + if case .coverPictureChanged(let v)? = kind {return v} + return Flipcash_Chat_V1_MetadataUpdate.CoverPictureChanged() + } + set {kind = .coverPictureChanged(newValue)} + } + public var unknownFields = SwiftProtobuf.UnknownStorage() public enum OneOf_Kind: Equatable, Sendable { @@ -654,8 +744,9 @@ public struct Flipcash_Chat_V1_MetadataUpdate: Sendable { case lastActivityChanged(Flipcash_Chat_V1_MetadataUpdate.LastActivityChanged) case viewerStateChanged(Flipcash_Chat_V1_MetadataUpdate.ViewerStateChanged) case titleChanged(Flipcash_Chat_V1_MetadataUpdate.TitleChanged) - case pictureChanged(Flipcash_Chat_V1_MetadataUpdate.PictureChanged) + case profilePictureChanged(Flipcash_Chat_V1_MetadataUpdate.ProfilePictureChanged) case descriptionChanged(Flipcash_Chat_V1_MetadataUpdate.DescriptionChanged) + case coverPictureChanged(Flipcash_Chat_V1_MetadataUpdate.CoverPictureChanged) } @@ -742,31 +833,31 @@ public struct Flipcash_Chat_V1_MetadataUpdate: Sendable { public init() {} } - /// The chat's picture has changed (e.g. via Chat.EditChat). Delivered to - /// the chat's members, including the editor's other devices. Best-effort - /// and applied as received; a client that suspects a miss refetches the - /// chat via Chat.GetChat. - public struct PictureChanged: Sendable { + /// The chat's profile picture has changed (e.g. via Chat.EditChat). + /// Delivered to the chat's members, including the editor's other devices. + /// Best-effort and applied as received; a client that suspects a miss + /// refetches the chat via Chat.GetChat. + public struct ProfilePictureChanged: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. - /// The new picture, with the renditions the server derived, replacing - /// Metadata.picture. - public var newPicture: Flipcash_Blob_V1_Media { - get {return _newPicture ?? Flipcash_Blob_V1_Media()} - set {_newPicture = newValue} + /// The new profile picture, with the renditions the server derived, + /// replacing Metadata.profile_picture. + public var newProfilePicture: Flipcash_Blob_V1_Media { + get {return _newProfilePicture ?? Flipcash_Blob_V1_Media()} + set {_newProfilePicture = newValue} } - /// Returns true if `newPicture` has been explicitly set. - public var hasNewPicture: Bool {return self._newPicture != nil} - /// Clears the value of `newPicture`. Subsequent reads from it will return its default value. - public mutating func clearNewPicture() {self._newPicture = nil} + /// Returns true if `newProfilePicture` has been explicitly set. + public var hasNewProfilePicture: Bool {return self._newProfilePicture != nil} + /// Clears the value of `newProfilePicture`. Subsequent reads from it will return its default value. + public mutating func clearNewProfilePicture() {self._newProfilePicture = nil} public var unknownFields = SwiftProtobuf.UnknownStorage() public init() {} - fileprivate var _newPicture: Flipcash_Blob_V1_Media? = nil + fileprivate var _newProfilePicture: Flipcash_Blob_V1_Media? = nil } /// The chat's description has changed (e.g. via Chat.EditChat). Delivered @@ -787,13 +878,42 @@ public struct Flipcash_Chat_V1_MetadataUpdate: Sendable { public init() {} } + /// The chat's cover picture has changed (e.g. via Chat.EditChat). Delivered + /// to the chat's members, including the editor's other devices. + /// Best-effort and applied as received; a client that suspects a miss + /// refetches the chat via Chat.GetChat. + public struct CoverPictureChanged: Sendable { + // SwiftProtobuf.Message conformance is added in an extension below. See the + // `Message` and `Message+*Additions` files in the SwiftProtobuf library for + // methods supported on all messages. + + /// The new cover picture, with the renditions the server derived, + /// replacing Metadata.cover_picture. + public var newCoverPicture: Flipcash_Blob_V1_Media { + get {return _newCoverPicture ?? Flipcash_Blob_V1_Media()} + set {_newCoverPicture = newValue} + } + /// Returns true if `newCoverPicture` has been explicitly set. + public var hasNewCoverPicture: Bool {return self._newCoverPicture != nil} + /// Clears the value of `newCoverPicture`. Subsequent reads from it will return its default value. + public mutating func clearNewCoverPicture() {self._newCoverPicture = nil} + + public var unknownFields = SwiftProtobuf.UnknownStorage() + + public init() {} + + fileprivate var _newCoverPicture: Flipcash_Blob_V1_Media? = nil + } + public init() {} } /// RosterUpdate is a best-effort, real-time change to a chat's roster — a /// member joining (e.g. via Chat.JoinChat, or as the first member via -/// Chat.StartChat) or leaving (e.g. via Chat.LeaveChat). It is delivered to -/// the chat's members, including the affected user's other devices. +/// Chat.StartChat) or leaving (e.g. via Chat.LeaveChat), or a change the +/// recipient is not shown, which carries the summary alone (see +/// MembershipChanged). It is delivered to the chat's members, including the +/// affected user's other devices. /// /// Roster changes are a convergent overlay, so these ride the event stream /// OUTSIDE the gap-detected event log. Clients apply them by roster_summary @@ -825,6 +945,14 @@ public struct Flipcash_Chat_V1_RosterUpdate: Sendable { set {kind = .memberLeft(newValue)} } + public var membershipChanged: Flipcash_Chat_V1_RosterUpdate.MembershipChanged { + get { + if case .membershipChanged(let v)? = kind {return v} + return Flipcash_Chat_V1_RosterUpdate.MembershipChanged() + } + set {kind = .membershipChanged(newValue)} + } + /// The chat's roster summary after this change, applied by version as /// described above. public var rosterSummary: Flipcash_Chat_V1_RosterSummary { @@ -841,6 +969,7 @@ public struct Flipcash_Chat_V1_RosterUpdate: Sendable { public enum OneOf_Kind: Equatable, Sendable { case memberJoined(Flipcash_Chat_V1_RosterUpdate.MemberJoined) case memberLeft(Flipcash_Chat_V1_RosterUpdate.MemberLeft) + case membershipChanged(Flipcash_Chat_V1_RosterUpdate.MembershipChanged) } @@ -914,6 +1043,26 @@ public struct Flipcash_Chat_V1_RosterUpdate: Sendable { fileprivate var _userID: Flipcash_Common_V1_UserId? = nil } + /// The roster changed, but the change is not disclosed to the recipient: + /// the update names no member and carries no member to add or remove. The + /// recipient applies the enclosing roster_summary by version like any + /// other roster update, so member_count and version stay current, and + /// leaves its cached member list as it is. Having applied it, the + /// recipient holds the new version, so it is not a version to reconcile + /// by refetching the roster. + /// + /// It is never delivered to the user whose membership changed: their own + /// devices receive MemberJoined or MemberLeft for it. + public struct MembershipChanged: Sendable { + // SwiftProtobuf.Message conformance is added in an extension below. See the + // `Message` and `Message+*Additions` files in the SwiftProtobuf library for + // methods supported on all messages. + + public var unknownFields = SwiftProtobuf.UnknownStorage() + + public init() {} + } + public init() {} fileprivate var _rosterSummary: Flipcash_Chat_V1_RosterSummary? = nil @@ -1287,8 +1436,8 @@ public struct Flipcash_Chat_V1_Lobby: Sendable { // methods supported on all messages. /// The chat, as a user who is not a member sees it: its record (title, - /// picture, roster summary, creator) with in_lobby set, and none of its - /// members or messaging state. + /// profile picture, roster summary, creator) with in_lobby set, and none of + /// its members or messaging state. public var chat: Flipcash_Chat_V1_Metadata { get {return _chat ?? Flipcash_Chat_V1_Metadata()} set {_chat = newValue} @@ -1427,7 +1576,7 @@ extension Flipcash_Chat_V1_ChatType: SwiftProtobuf._ProtoNameProviding { extension Flipcash_Chat_V1_Metadata: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".Metadata" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{3}chat_id\0\u{1}type\0\u{1}members\0\u{3}last_message\0\u{3}last_activity\0\u{3}latest_event_sequence\0\u{3}is_hidden\0\u{1}title\0\u{1}picture\0\u{3}roster_summary\0\u{1}rules\0\u{3}viewer_state\0\u{1}creator\0\u{3}is_private\0\u{3}in_lobby\0\u{1}description\0\u{4}T\u{1}use_e2ee\0") + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{3}chat_id\0\u{1}type\0\u{1}members\0\u{3}last_message\0\u{3}last_activity\0\u{3}latest_event_sequence\0\u{3}is_hidden\0\u{1}title\0\u{3}profile_picture\0\u{3}roster_summary\0\u{1}rules\0\u{3}viewer_state\0\u{1}creator\0\u{3}is_private\0\u{3}in_lobby\0\u{1}description\0\u{3}cover_picture\0\u{4}S\u{1}use_e2ee\0") fileprivate class _StorageClass { var _chatID: Flipcash_Common_V1_ChatId? = nil @@ -1438,7 +1587,7 @@ extension Flipcash_Chat_V1_Metadata: SwiftProtobuf.Message, SwiftProtobuf._Messa var _latestEventSequence: UInt64 = 0 var _isHidden: Bool = false var _title: String = String() - var _picture: Flipcash_Blob_V1_Media? = nil + var _profilePicture: Flipcash_Blob_V1_Media? = nil var _rosterSummary: Flipcash_Chat_V1_RosterSummary? = nil var _rules: Flipcash_Chat_V1_Rules? = nil var _viewerState: Flipcash_Chat_V1_ViewerState? = nil @@ -1446,6 +1595,7 @@ extension Flipcash_Chat_V1_Metadata: SwiftProtobuf.Message, SwiftProtobuf._Messa var _isPrivate: Bool = false var _inLobby: Bool = false var _description_p: String = String() + var _coverPicture: Flipcash_Blob_V1_Media? = nil var _useE2Ee: Bool = false // This property is used as the initial default value for new instances of the type. @@ -1465,7 +1615,7 @@ extension Flipcash_Chat_V1_Metadata: SwiftProtobuf.Message, SwiftProtobuf._Messa _latestEventSequence = source._latestEventSequence _isHidden = source._isHidden _title = source._title - _picture = source._picture + _profilePicture = source._profilePicture _rosterSummary = source._rosterSummary _rules = source._rules _viewerState = source._viewerState @@ -1473,6 +1623,7 @@ extension Flipcash_Chat_V1_Metadata: SwiftProtobuf.Message, SwiftProtobuf._Messa _isPrivate = source._isPrivate _inLobby = source._inLobby _description_p = source._description_p + _coverPicture = source._coverPicture _useE2Ee = source._useE2Ee } } @@ -1500,7 +1651,7 @@ extension Flipcash_Chat_V1_Metadata: SwiftProtobuf.Message, SwiftProtobuf._Messa case 6: try { try decoder.decodeSingularUInt64Field(value: &_storage._latestEventSequence) }() case 7: try { try decoder.decodeSingularBoolField(value: &_storage._isHidden) }() case 8: try { try decoder.decodeSingularStringField(value: &_storage._title) }() - case 9: try { try decoder.decodeSingularMessageField(value: &_storage._picture) }() + case 9: try { try decoder.decodeSingularMessageField(value: &_storage._profilePicture) }() case 10: try { try decoder.decodeSingularMessageField(value: &_storage._rosterSummary) }() case 11: try { try decoder.decodeSingularMessageField(value: &_storage._rules) }() case 12: try { try decoder.decodeSingularMessageField(value: &_storage._viewerState) }() @@ -1508,6 +1659,7 @@ extension Flipcash_Chat_V1_Metadata: SwiftProtobuf.Message, SwiftProtobuf._Messa case 14: try { try decoder.decodeSingularBoolField(value: &_storage._isPrivate) }() case 15: try { try decoder.decodeSingularBoolField(value: &_storage._inLobby) }() case 16: try { try decoder.decodeSingularStringField(value: &_storage._description_p) }() + case 17: try { try decoder.decodeSingularMessageField(value: &_storage._coverPicture) }() case 100: try { try decoder.decodeSingularBoolField(value: &_storage._useE2Ee) }() default: break } @@ -1545,7 +1697,7 @@ extension Flipcash_Chat_V1_Metadata: SwiftProtobuf.Message, SwiftProtobuf._Messa if !_storage._title.isEmpty { try visitor.visitSingularStringField(value: _storage._title, fieldNumber: 8) } - try { if let v = _storage._picture { + try { if let v = _storage._profilePicture { try visitor.visitSingularMessageField(value: v, fieldNumber: 9) } }() try { if let v = _storage._rosterSummary { @@ -1569,6 +1721,9 @@ extension Flipcash_Chat_V1_Metadata: SwiftProtobuf.Message, SwiftProtobuf._Messa if !_storage._description_p.isEmpty { try visitor.visitSingularStringField(value: _storage._description_p, fieldNumber: 16) } + try { if let v = _storage._coverPicture { + try visitor.visitSingularMessageField(value: v, fieldNumber: 17) + } }() if _storage._useE2Ee != false { try visitor.visitSingularBoolField(value: _storage._useE2Ee, fieldNumber: 100) } @@ -1589,7 +1744,7 @@ extension Flipcash_Chat_V1_Metadata: SwiftProtobuf.Message, SwiftProtobuf._Messa if _storage._latestEventSequence != rhs_storage._latestEventSequence {return false} if _storage._isHidden != rhs_storage._isHidden {return false} if _storage._title != rhs_storage._title {return false} - if _storage._picture != rhs_storage._picture {return false} + if _storage._profilePicture != rhs_storage._profilePicture {return false} if _storage._rosterSummary != rhs_storage._rosterSummary {return false} if _storage._rules != rhs_storage._rules {return false} if _storage._viewerState != rhs_storage._viewerState {return false} @@ -1597,6 +1752,7 @@ extension Flipcash_Chat_V1_Metadata: SwiftProtobuf.Message, SwiftProtobuf._Messa if _storage._isPrivate != rhs_storage._isPrivate {return false} if _storage._inLobby != rhs_storage._inLobby {return false} if _storage._description_p != rhs_storage._description_p {return false} + if _storage._coverPicture != rhs_storage._coverPicture {return false} if _storage._useE2Ee != rhs_storage._useE2Ee {return false} return true } @@ -2081,6 +2237,90 @@ extension Flipcash_Chat_V1_MentionSuggestion: SwiftProtobuf.Message, SwiftProtob } } +extension Flipcash_Chat_V1_SampledChatter: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = _protobuf_package + ".SampledChatter" + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{3}user_profile\0\u{3}last_sent_at\0\u{3}is_creator\0") + + fileprivate class _StorageClass { + var _userProfile: Flipcash_Profile_V1_UserProfile? = nil + var _lastSentAt: SwiftProtobuf.Google_Protobuf_Timestamp? = nil + var _isCreator: Bool = false + + // This property is used as the initial default value for new instances of the type. + // The type itself is protecting the reference to its storage via CoW semantics. + // This will force a copy to be made of this reference when the first mutation occurs; + // hence, it is safe to mark this as `nonisolated(unsafe)`. + static nonisolated(unsafe) let defaultInstance = _StorageClass() + + private init() {} + + init(copying source: _StorageClass) { + _userProfile = source._userProfile + _lastSentAt = source._lastSentAt + _isCreator = source._isCreator + } + } + + fileprivate mutating func _uniqueStorage() -> _StorageClass { + if !isKnownUniquelyReferenced(&_storage) { + _storage = _StorageClass(copying: _storage) + } + return _storage + } + + public mutating func decodeMessage(decoder: inout D) throws { + _ = _uniqueStorage() + try withExtendedLifetime(_storage) { (_storage: _StorageClass) in + while let fieldNumber = try decoder.nextFieldNumber() { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every case branch when no optimizations are + // enabled. https://github.com/apple/swift-protobuf/issues/1034 + switch fieldNumber { + case 1: try { try decoder.decodeSingularMessageField(value: &_storage._userProfile) }() + case 2: try { try decoder.decodeSingularMessageField(value: &_storage._lastSentAt) }() + case 3: try { try decoder.decodeSingularBoolField(value: &_storage._isCreator) }() + default: break + } + } + } + } + + public func traverse(visitor: inout V) throws { + try withExtendedLifetime(_storage) { (_storage: _StorageClass) in + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every if/case branch local when no optimizations + // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and + // https://github.com/apple/swift-protobuf/issues/1182 + try { if let v = _storage._userProfile { + try visitor.visitSingularMessageField(value: v, fieldNumber: 1) + } }() + try { if let v = _storage._lastSentAt { + try visitor.visitSingularMessageField(value: v, fieldNumber: 2) + } }() + if _storage._isCreator != false { + try visitor.visitSingularBoolField(value: _storage._isCreator, fieldNumber: 3) + } + } + try unknownFields.traverse(visitor: &visitor) + } + + public static func ==(lhs: Flipcash_Chat_V1_SampledChatter, rhs: Flipcash_Chat_V1_SampledChatter) -> Bool { + if lhs._storage !== rhs._storage { + let storagesAreEqual: Bool = withExtendedLifetime((lhs._storage, rhs._storage)) { (_args: (_StorageClass, _StorageClass)) in + let _storage = _args.0 + let rhs_storage = _args.1 + if _storage._userProfile != rhs_storage._userProfile {return false} + if _storage._lastSentAt != rhs_storage._lastSentAt {return false} + if _storage._isCreator != rhs_storage._isCreator {return false} + return true + } + if !storagesAreEqual {return false} + } + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} + extension Flipcash_Chat_V1_RosterSummary: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".RosterSummary" public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{3}member_count\0\u{1}version\0") @@ -2118,7 +2358,7 @@ extension Flipcash_Chat_V1_RosterSummary: SwiftProtobuf.Message, SwiftProtobuf._ extension Flipcash_Chat_V1_MetadataUpdate: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".MetadataUpdate" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{3}full_refresh\0\u{3}last_activity_changed\0\u{3}viewer_state_changed\0\u{3}title_changed\0\u{3}picture_changed\0\u{3}description_changed\0") + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{3}full_refresh\0\u{3}last_activity_changed\0\u{3}viewer_state_changed\0\u{3}title_changed\0\u{3}profile_picture_changed\0\u{3}description_changed\0\u{3}cover_picture_changed\0") public mutating func decodeMessage(decoder: inout D) throws { while let fieldNumber = try decoder.nextFieldNumber() { @@ -2179,16 +2419,16 @@ extension Flipcash_Chat_V1_MetadataUpdate: SwiftProtobuf.Message, SwiftProtobuf. } }() case 5: try { - var v: Flipcash_Chat_V1_MetadataUpdate.PictureChanged? + var v: Flipcash_Chat_V1_MetadataUpdate.ProfilePictureChanged? var hadOneofValue = false if let current = self.kind { hadOneofValue = true - if case .pictureChanged(let m) = current {v = m} + if case .profilePictureChanged(let m) = current {v = m} } try decoder.decodeSingularMessageField(value: &v) if let v = v { if hadOneofValue {try decoder.handleConflictingOneOf()} - self.kind = .pictureChanged(v) + self.kind = .profilePictureChanged(v) } }() case 6: try { @@ -2204,6 +2444,19 @@ extension Flipcash_Chat_V1_MetadataUpdate: SwiftProtobuf.Message, SwiftProtobuf. self.kind = .descriptionChanged(v) } }() + case 7: try { + var v: Flipcash_Chat_V1_MetadataUpdate.CoverPictureChanged? + var hadOneofValue = false + if let current = self.kind { + hadOneofValue = true + if case .coverPictureChanged(let m) = current {v = m} + } + try decoder.decodeSingularMessageField(value: &v) + if let v = v { + if hadOneofValue {try decoder.handleConflictingOneOf()} + self.kind = .coverPictureChanged(v) + } + }() default: break } } @@ -2231,14 +2484,18 @@ extension Flipcash_Chat_V1_MetadataUpdate: SwiftProtobuf.Message, SwiftProtobuf. guard case .titleChanged(let v)? = self.kind else { preconditionFailure() } try visitor.visitSingularMessageField(value: v, fieldNumber: 4) }() - case .pictureChanged?: try { - guard case .pictureChanged(let v)? = self.kind else { preconditionFailure() } + case .profilePictureChanged?: try { + guard case .profilePictureChanged(let v)? = self.kind else { preconditionFailure() } try visitor.visitSingularMessageField(value: v, fieldNumber: 5) }() case .descriptionChanged?: try { guard case .descriptionChanged(let v)? = self.kind else { preconditionFailure() } try visitor.visitSingularMessageField(value: v, fieldNumber: 6) }() + case .coverPictureChanged?: try { + guard case .coverPictureChanged(let v)? = self.kind else { preconditionFailure() } + try visitor.visitSingularMessageField(value: v, fieldNumber: 7) + }() case nil: break } try unknownFields.traverse(visitor: &visitor) @@ -2383,9 +2640,9 @@ extension Flipcash_Chat_V1_MetadataUpdate.TitleChanged: SwiftProtobuf.Message, S } } -extension Flipcash_Chat_V1_MetadataUpdate.PictureChanged: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - public static let protoMessageName: String = Flipcash_Chat_V1_MetadataUpdate.protoMessageName + ".PictureChanged" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{3}new_picture\0") +extension Flipcash_Chat_V1_MetadataUpdate.ProfilePictureChanged: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = Flipcash_Chat_V1_MetadataUpdate.protoMessageName + ".ProfilePictureChanged" + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{3}new_profile_picture\0") public mutating func decodeMessage(decoder: inout D) throws { while let fieldNumber = try decoder.nextFieldNumber() { @@ -2393,7 +2650,7 @@ extension Flipcash_Chat_V1_MetadataUpdate.PictureChanged: SwiftProtobuf.Message, // allocates stack space for every case branch when no optimizations are // enabled. https://github.com/apple/swift-protobuf/issues/1034 switch fieldNumber { - case 1: try { try decoder.decodeSingularMessageField(value: &self._newPicture) }() + case 1: try { try decoder.decodeSingularMessageField(value: &self._newProfilePicture) }() default: break } } @@ -2404,14 +2661,14 @@ extension Flipcash_Chat_V1_MetadataUpdate.PictureChanged: SwiftProtobuf.Message, // allocates stack space for every if/case branch local when no optimizations // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and // https://github.com/apple/swift-protobuf/issues/1182 - try { if let v = self._newPicture { + try { if let v = self._newProfilePicture { try visitor.visitSingularMessageField(value: v, fieldNumber: 1) } }() try unknownFields.traverse(visitor: &visitor) } - public static func ==(lhs: Flipcash_Chat_V1_MetadataUpdate.PictureChanged, rhs: Flipcash_Chat_V1_MetadataUpdate.PictureChanged) -> Bool { - if lhs._newPicture != rhs._newPicture {return false} + public static func ==(lhs: Flipcash_Chat_V1_MetadataUpdate.ProfilePictureChanged, rhs: Flipcash_Chat_V1_MetadataUpdate.ProfilePictureChanged) -> Bool { + if lhs._newProfilePicture != rhs._newProfilePicture {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true } @@ -2447,9 +2704,43 @@ extension Flipcash_Chat_V1_MetadataUpdate.DescriptionChanged: SwiftProtobuf.Mess } } +extension Flipcash_Chat_V1_MetadataUpdate.CoverPictureChanged: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = Flipcash_Chat_V1_MetadataUpdate.protoMessageName + ".CoverPictureChanged" + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{3}new_cover_picture\0") + + public mutating func decodeMessage(decoder: inout D) throws { + while let fieldNumber = try decoder.nextFieldNumber() { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every case branch when no optimizations are + // enabled. https://github.com/apple/swift-protobuf/issues/1034 + switch fieldNumber { + case 1: try { try decoder.decodeSingularMessageField(value: &self._newCoverPicture) }() + default: break + } + } + } + + public func traverse(visitor: inout V) throws { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every if/case branch local when no optimizations + // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and + // https://github.com/apple/swift-protobuf/issues/1182 + try { if let v = self._newCoverPicture { + try visitor.visitSingularMessageField(value: v, fieldNumber: 1) + } }() + try unknownFields.traverse(visitor: &visitor) + } + + public static func ==(lhs: Flipcash_Chat_V1_MetadataUpdate.CoverPictureChanged, rhs: Flipcash_Chat_V1_MetadataUpdate.CoverPictureChanged) -> Bool { + if lhs._newCoverPicture != rhs._newCoverPicture {return false} + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} + extension Flipcash_Chat_V1_RosterUpdate: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".RosterUpdate" - public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{3}member_joined\0\u{3}member_left\0\u{4}\u{8}roster_summary\0") + public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{3}member_joined\0\u{3}member_left\0\u{3}membership_changed\0\u{4}\u{7}roster_summary\0") public mutating func decodeMessage(decoder: inout D) throws { while let fieldNumber = try decoder.nextFieldNumber() { @@ -2483,6 +2774,19 @@ extension Flipcash_Chat_V1_RosterUpdate: SwiftProtobuf.Message, SwiftProtobuf._M self.kind = .memberLeft(v) } }() + case 3: try { + var v: Flipcash_Chat_V1_RosterUpdate.MembershipChanged? + var hadOneofValue = false + if let current = self.kind { + hadOneofValue = true + if case .membershipChanged(let m) = current {v = m} + } + try decoder.decodeSingularMessageField(value: &v) + if let v = v { + if hadOneofValue {try decoder.handleConflictingOneOf()} + self.kind = .membershipChanged(v) + } + }() case 10: try { try decoder.decodeSingularMessageField(value: &self._rosterSummary) }() default: break } @@ -2503,6 +2807,10 @@ extension Flipcash_Chat_V1_RosterUpdate: SwiftProtobuf.Message, SwiftProtobuf._M guard case .memberLeft(let v)? = self.kind else { preconditionFailure() } try visitor.visitSingularMessageField(value: v, fieldNumber: 2) }() + case .membershipChanged?: try { + guard case .membershipChanged(let v)? = self.kind else { preconditionFailure() } + try visitor.visitSingularMessageField(value: v, fieldNumber: 3) + }() case nil: break } try { if let v = self._rosterSummary { @@ -2592,6 +2900,25 @@ extension Flipcash_Chat_V1_RosterUpdate.MemberLeft: SwiftProtobuf.Message, Swift } } +extension Flipcash_Chat_V1_RosterUpdate.MembershipChanged: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + public static let protoMessageName: String = Flipcash_Chat_V1_RosterUpdate.protoMessageName + ".MembershipChanged" + public static let _protobuf_nameMap = SwiftProtobuf._NameMap() + + public mutating func decodeMessage(decoder: inout D) throws { + // Load everything into unknown fields + while try decoder.nextFieldNumber() != nil {} + } + + public func traverse(visitor: inout V) throws { + try unknownFields.traverse(visitor: &visitor) + } + + public static func ==(lhs: Flipcash_Chat_V1_RosterUpdate.MembershipChanged, rhs: Flipcash_Chat_V1_RosterUpdate.MembershipChanged) -> Bool { + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} + extension Flipcash_Chat_V1_RosterUpdateBatch: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".RosterUpdateBatch" public static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{3}roster_updates\0") diff --git a/flipcash2.lock b/flipcash2.lock index cae8c20..9dc3c84 100644 --- a/flipcash2.lock +++ b/flipcash2.lock @@ -1,4 +1,4 @@ # Pinned upstream contract. Regenerate with scripts/sync-protos.sh . upstream: code-payments/flipcash2-protobuf-api -commit: 3bb442d359dd8452b4e3eca5f5c1ca463e7f5a4b -subject: Add support for group descriptions (#134) +commit: 9d44350b8d4d8eda9d63cff405238bd0e2920409 +subject: Add support for featured groups (#138) diff --git a/proto/blob/v1/model.proto b/proto/blob/v1/model.proto index 4b8a40b..a5b1b28 100644 --- a/proto/blob/v1/model.proto +++ b/proto/blob/v1/model.proto @@ -371,8 +371,8 @@ message AccessContext { // The caller is accessing these blobs from this chat's public profile. // Authorized iff the blob is a rendition of that chat's CURRENT profile - // picture — a profile grants nothing else, and a superseded picture's - // renditions stop resolving through it. + // picture or cover picture — a profile grants nothing else, and a + // superseded picture's renditions stop resolving through it. common.v1.ChatId chat_profile = 3 [(validate.rules).message.required = true]; } } diff --git a/proto/chat/v1/chat_service.proto b/proto/chat/v1/chat_service.proto index 7bddc6e..fffc873 100644 --- a/proto/chat/v1/chat_service.proto +++ b/proto/chat/v1/chat_service.proto @@ -77,6 +77,10 @@ service Chat { // being read. Every page is served only for groups the caller is still a // member of at the time of that page; a group the caller left between // pages is dropped, and its removal arrives on the stream. + // + // The feed is meant for list views, so a chat's cover_picture may be + // omitted from it (see Metadata). Fetch it with GetChat when the client + // shows the chat's profile view. rpc GetGroupChatFeed(GetGroupChatFeedRequest) returns (GetGroupChatFeedResponse); // GetRoster pages a chat's roster, most recently joined first. Every @@ -103,11 +107,46 @@ service Chat { // carry none: group pointer advances are never broadcast, so a page of // them would be stale as soon as it was served. // - // Requires that the caller may read the chat: a member, or a non-member - // a group's listener rules admit. A viewer who may only preview the chat - // is DENIED. + // Requires that the caller is a member of the chat. Anyone else is + // DENIED, including a non-member whom a group's listener rules admit to + // read its messages: who is in a chat is shown only to its members. rpc GetRoster(GetRosterRequest) returns (GetRosterResponse); + // SampleChatters returns a short sample of a public group's members to + // show: its creator first, while they are a member, then the members who + // have sent a message most recently, most recent first. Members who have + // not sent a message recently are not in it. The caller is included like + // any other member, and so are users the caller has blocked: the sample + // shows who is in the chat, not who may be mentioned (see + // GetMentionSuggestions). + // + // Unlike the roster (see GetRoster), the sample is public: it is part of + // how a group presents itself, as its title and pictures are, and is + // returned to anyone who asks, member or not, registered or not. Auth is + // optional; when set it must be valid, but it changes nothing about what + // is returned. + // + // Everyone in the sample is a member of the group as of the read, which + // may trail a join or departure by a moment: it is a subset of the roster + // GetRoster pages, never someone who never joined, though someone who + // left a moment ago may still be in it. It is not the whole roster: it is neither complete nor + // paged and carries no roster version, and has_more is the only + // indication of what lies past it. The server decides how many to + // return, up to 100; neither the size nor the order after the creator is + // part of the contract. + // + // It is a snapshot, which a client may show as it is. A client that wants + // it live, and streams the group's events (as a member, or through a chat + // preview), may instead keep it fresh between fetches by moving the + // sender of each new message to the front, adding them if absent, since + // anyone who sends is a member. Departures are not announced to the other + // members (see RosterUpdate.MembershipChanged), so a member who has left + // may remain in a client's copy until it fetches again. + // + // Only for public groups: a private group (see Metadata.is_private) and a + // DM are DENIED, whoever asks. + rpc SampleChatters(SampleChattersRequest) returns (SampleChattersResponse); + // GetMentionSuggestions returns people the caller may want to @mention in // a group chat, ranked by the server, most relevant first. Today that is // the group's most recent senders, most recent first, including people @@ -154,17 +193,18 @@ service Chat { // Only a group chat may be edited, and only by a member the server permits // to edit it, as reported by ViewerState.Permissions.can_edit; anyone else // is DENIED. A new title or description is moderated like StartChat's. A - // new picture is a blob the caller has already uploaded via - // BlobStorage: the client uploads only the ORIGINAL and passes the - // resulting BlobId once the blob is READY, and the server derives the - // remaining renditions. Setting a field to the value the chat already has - // is a no-op for that field, and a request that sets nothing is a no-op - // that returns OK. + // new profile picture or cover picture is a blob the caller has already + // uploaded via BlobStorage: the client uploads only the ORIGINAL and + // passes the resulting BlobId once the blob is READY, and the server + // derives the remaining renditions. Setting a field to the value the chat + // already has is a no-op for that field, and a request that sets nothing + // is a no-op that returns OK. // // Every real change reaches the chat's members, including the caller's // other devices, on the event stream as one MetadataUpdate per field - // changed: TitleChanged for the title, PictureChanged for the picture, - // DescriptionChanged for the description. + // changed: TitleChanged for the title, ProfilePictureChanged for the + // profile picture, DescriptionChanged for the description, + // CoverPictureChanged for the cover picture. rpc EditChat(EditChatRequest) returns (EditChatResponse); // MuteChat mutes a chat for the caller, until a time or indefinitely. @@ -291,6 +331,48 @@ service Chat { // SetKeyEnvelope, as described on KeyEnvelope, and keeps attempting that // until it succeeds. rpc GetKeyEnvelope(GetKeyEnvelopeRequest) returns (GetKeyEnvelopeResponse); + + // SetFeaturedGroups replaces the caller's featured groups: an ordered + // list of public group chats they show on their profile, which anyone can + // fetch with GetFeaturedGroups. The list is written whole, so the request + // carries every group the caller wants featured, in the order to show + // them, and an empty list clears it. Setting the list already stored is a + // no-op that returns OK. + // + // Featuring a group says nothing about the caller's place in it: a group + // may be featured whether or not the caller is a member, and leaving a + // group does not remove it from the list. + // + // Only public groups may be featured: when a group in the request is + // private (see Metadata.is_private), nothing is written and the result + // is DENIED. A group never becomes private after it is created, so a + // featured group stays public. Every group must exist: when one does not, + // nothing is written and the result is NOT_FOUND. A DM's ID, or a group + // named more than once, is an invalid argument. + // + // Nothing is published: the caller's other devices see the change on + // their next GetFeaturedGroups. + rpc SetFeaturedGroups(SetFeaturedGroupsRequest) returns (SetFeaturedGroupsResponse); + + // GetFeaturedGroups returns a user's featured groups (see + // SetFeaturedGroups), in the order the user set them. + // + // Each group is a public group (see SetFeaturedGroups), returned as its + // record as a list view shows it: chat_id, type, title, description, + // profile_picture, roster_summary, rules, creator and last_activity. Nothing about the viewer's place in the + // group is set (members, is_hidden, viewer_state, in_lobby), nor its + // messaging state (last_message, latest_event_sequence), nor its + // cover_picture: a client opening a group fetches the rest with GetChat. + // + // The list is public, like the user's profile, and the same for every + // viewer. Auth is optional; when set it must be valid, but it changes + // nothing about what is returned. A group that no longer exists is left + // out. + // + // The user is identified by username, the handle a profile is opened by, + // so a client can fetch a profile (see profile.v1.Profile.GetProfile) and + // its featured groups at once. + rpc GetFeaturedGroups(GetFeaturedGroupsRequest) returns (GetFeaturedGroupsResponse); } message GetChatRequest { @@ -299,11 +381,12 @@ message GetChatRequest { // What the client intends to render of the chat's messaging state — its // last_message and latest_event_sequence — and so whether they may be // returned redacted (see messaging.v1.ViewMode). A group's record (title, - // description, picture, rules, roster summary) is returned to every - // registered user whatever the mode; the mode decides only the messaging - // state, which is withheld from a viewer who may not read the chat under - // it. Unset (FULL) is the pre-redaction contract: messaging state for a - // viewer who may read the chat in full, the bare record for anyone else. + // description, profile picture, cover picture, rules, roster summary) is + // returned to every registered user whatever the mode; the mode decides + // only the messaging state, which is withheld from a viewer who may not + // read the chat under it. Unset (FULL) is the pre-redaction contract: + // messaging state for a viewer who may read the chat in full, the bare + // record for anyone else. // // Must be REDACTED when auth is unset; any other mode is DENIED. messaging.v1.ViewMode view_mode = 2 [(validate.rules).enum = { @@ -472,6 +555,37 @@ message GetRosterResponse { bool has_more = 5; } +message SampleChattersRequest { + common.v1.ChatId chat_id = 1 [(validate.rules).message.required = true]; + + // Optional. When set it must be valid, but the sample is the same with + // or without it (see Chat.SampleChatters). + common.v1.Auth auth = 10; +} + +message SampleChattersResponse { + Result result = 1; + enum Result { + OK = 0; + DENIED = 1; + NOT_FOUND = 2; + } + + // The sample, every one a member as of the read: the creator first, when + // they are a member, then the most recent senders, most recent first. + // Set when result is OK. + repeated SampledChatter chatters = 2 [(validate.rules).repeated = { + min_items: 0 + max_items: 100 + }]; + + // Whether the group may have more members who have sent recently than + // the sample holds, for a client to show that there are others. It is + // true when the server knows of more, and also when it stopped looking + // before it could tell. Set when result is OK. + bool has_more = 3; +} + message GetMentionSuggestionsRequest { common.v1.ChatId chat_id = 1 [(validate.rules).message.required = true]; @@ -514,9 +628,9 @@ message StartChatRequest { max_len: 64 }]; - // The blob holding the ORIGINAL picture the caller uploaded. Optional. - // If set, it must be owned by the caller and READY. - blob.v1.BlobId picture = 2; + // The blob holding the ORIGINAL profile picture the caller uploaded. + // Optional. If set, it must be owned by the caller and READY. + blob.v1.BlobId profile_picture = 2; // Rules governing participation in the chat. Optional; if not set, the // chat has no participation requirements. Caller must satisfy the rules @@ -528,6 +642,10 @@ message StartChatRequest { string description = 4 [(validate.rules).string = { max_len: 160 }]; + + // The blob holding the ORIGINAL cover picture the caller uploaded. + // Optional. If set, it must be owned by the caller and READY. + blob.v1.BlobId cover_picture = 5; } // Parameters for creating a private group chat (see Metadata.is_private): @@ -558,15 +676,19 @@ message StartChatRequest { max_len: 64 }]; - // The blob holding the ORIGINAL picture the caller uploaded. Optional. - // If set, it must be owned by the caller and READY. - blob.v1.BlobId picture = 2; + // The blob holding the ORIGINAL profile picture the caller uploaded. + // Optional. If set, it must be owned by the caller and READY. + blob.v1.BlobId profile_picture = 2; // Description for the chat. Optional; empty sets none. Moderated like // the title. string description = 3 [(validate.rules).string = { max_len: 160 }]; + + // The blob holding the ORIGINAL cover picture the caller uploaded. + // Optional. If set, it must be owned by the caller and READY. + blob.v1.BlobId cover_picture = 4; } // Key for retrying this request safely. A retry with the same key from the @@ -580,18 +702,19 @@ message StartChatRequest { message StartChatResponse { Result result = 1; enum Result { - OK = 0; - DENIED = 1; - TITLE_MODERATED = 2; - PICTURE_BLOB_NOT_ACCEPTED = 3; - INVALID_RULES = 4; - RULES_NOT_SATISFIED = 5; - DESCRIPTION_MODERATED = 6; + OK = 0; + DENIED = 1; + TITLE_MODERATED = 2; + PROFILE_PICTURE_BLOB_NOT_ACCEPTED = 3; + INVALID_RULES = 4; + RULES_NOT_SATISFIED = 5; + DESCRIPTION_MODERATED = 6; + COVER_PICTURE_BLOB_NOT_ACCEPTED = 7; } // The metadata for the newly created chat, including the server-generated - // chat_id and any picture renditions the server derived. Set only when - // result == OK. + // chat_id and any profile picture or cover picture renditions the server + // derived. Set only when result == OK. Metadata chat = 2; // The best-fit category that tripped moderation, mirroring the Moderation @@ -641,12 +764,15 @@ message EditChatRequest { // The new title. Left unchanged when unset. Title title = 2; - // The new picture. Left unchanged when unset. - Picture picture = 3; + // The new profile picture. Left unchanged when unset. + ProfilePicture profile_picture = 3; // The new description. Left unchanged when unset. Description description = 4; + // The new cover picture. Left unchanged when unset. + CoverPicture cover_picture = 5; + message Title { string value = 1 [(validate.rules).string = { min_len: 1 @@ -654,10 +780,10 @@ message EditChatRequest { }]; } - message Picture { - // The blob holding the ORIGINAL picture the caller uploaded. It must be - // owned by the caller and READY; the server derives the remaining - // renditions from it. + message ProfilePicture { + // The blob holding the ORIGINAL profile picture the caller uploaded. It + // must be owned by the caller and READY; the server derives the + // remaining renditions from it. blob.v1.BlobId blob_id = 1 [(validate.rules).message.required = true]; } @@ -668,23 +794,31 @@ message EditChatRequest { }]; } + message CoverPicture { + // The blob holding the ORIGINAL cover picture the caller uploaded. It + // must be owned by the caller and READY; the server derives the + // remaining renditions from it. + blob.v1.BlobId blob_id = 1 [(validate.rules).message.required = true]; + } + common.v1.Auth auth = 10 [(validate.rules).message.required = true]; } message EditChatResponse { Result result = 1; enum Result { - OK = 0; - DENIED = 1; - NOT_FOUND = 2; - TITLE_MODERATED = 3; - PICTURE_BLOB_NOT_ACCEPTED = 4; - DESCRIPTION_MODERATED = 5; + OK = 0; + DENIED = 1; + NOT_FOUND = 2; + TITLE_MODERATED = 3; + PROFILE_PICTURE_BLOB_NOT_ACCEPTED = 4; + COVER_PICTURE_BLOB_NOT_ACCEPTED = 5; + DESCRIPTION_MODERATED = 6; } // The metadata for the chat after the edit, as seen by the caller, - // including any picture renditions the server derived. Set only when - // result == OK. + // including any profile picture or cover picture renditions the server + // derived. Set only when result == OK. Metadata chat = 2; // The best-fit category that tripped moderation, mirroring the Moderation @@ -898,3 +1032,60 @@ message GetKeyEnvelopeResponse { // only when result == OK. common.v1.UserId wrapped_by = 3; } + +message SetFeaturedGroupsRequest { + // The groups to feature, in the order to show them. Every ID must name a + // public group chat, and none may repeat. Empty clears the featured + // groups. + repeated common.v1.ChatId chat_ids = 1 [(validate.rules).repeated = { + min_items: 0 + max_items: 10 + }]; + + common.v1.Auth auth = 10 [(validate.rules).message.required = true]; +} + +message SetFeaturedGroupsResponse { + Result result = 1; + enum Result { + OK = 0; + DENIED = 1; // A group in the request is private; nothing was written + NOT_FOUND = 2; // A group in the request does not exist; nothing was written + } + + // The caller's featured groups after the write, as GetFeaturedGroups + // returns them. Set only when result == OK. + repeated Metadata featured_groups = 2 [(validate.rules).repeated = { + min_items: 0 + max_items: 10 + }]; +} + +message GetFeaturedGroupsRequest { + // The user whose featured groups are being fetched. Only a username is + // supported for now; the oneof leaves room for other identifiers. + oneof identifier { + option (validate.required) = true; + + common.v1.Username username = 1; + } + + // Optional. When set it must be valid, but the list is the same with or + // without it (see Chat.GetFeaturedGroups). + common.v1.Auth auth = 10; +} + +message GetFeaturedGroupsResponse { + Result result = 1; + enum Result { + OK = 0; + NOT_FOUND = 1; // No user holds the username + } + + // The user's featured groups, in their order. Empty when they feature + // none. Set only when result == OK. + repeated Metadata featured_groups = 2 [(validate.rules).repeated = { + min_items: 0 + max_items: 10 + }]; +} diff --git a/proto/chat/v1/model.proto b/proto/chat/v1/model.proto index b9fd1e9..a721941 100644 --- a/proto/chat/v1/model.proto +++ b/proto/chat/v1/model.proto @@ -65,8 +65,15 @@ message Metadata { max_len: 64 }]; - // Picture for this chat. Only supported for group chats - blob.v1.Media picture = 9; + // The chat's profile picture — the avatar shown for it in chat lists and + // headers — as the set of renditions it is stored as. Only supported for + // group chats. Not to be confused with cover_picture, the banner shown + // behind the chat's profile view. + // + // Set it on creation (see StartChatRequest) or with Chat.EditChat. To + // fetch its bytes as a non-member, a GetBlobs call must carry a + // blob.v1.AccessContext whose `chat_profile` scope names this chat. + blob.v1.Media profile_picture = 9; // Chat roster summary RosterSummary roster_summary = 10 [(validate.rules).message.required = true]; @@ -112,10 +119,32 @@ message Metadata { // see the chat, including in its public view. // // Set it on creation (see StartChatRequest) or with Chat.EditChat. + // + // Unlike cover_picture, it is carried by the feed RPCs meant for list + // views (Chat.GetDmChatFeed, Chat.GetGroupChatFeed) too, so a list row + // may show it, and an empty value there means none is set. string description = 16 [(validate.rules).string = { max_len: 160 }]; + // The chat's cover picture — the banner shown behind the chat's profile + // view — as the set of renditions it is stored as, like + // profile_picture. Only supported for group chats. Unset when none is + // set. Part of the group's record, like profile_picture, so it is + // returned to every viewer who can see the chat, including in its public + // view. + // + // Set it on creation (see StartChatRequest) or with Chat.EditChat. To + // fetch its bytes as a non-member, a GetBlobs call must carry a + // blob.v1.AccessContext whose `chat_profile` scope names this chat, + // exactly as for profile_picture. + // + // It may be unset on a chat returned by a feed RPC meant for list views + // (Chat.GetDmChatFeed, Chat.GetGroupChatFeed), so an unset value there + // does not mean none is set. Fetch it with Chat.GetChat, and don't let a + // feed result clear a cover picture the client already holds. + blob.v1.Media cover_picture = 17; + // Whether messages in this chat are end-to-end encrypted (see // messaging.v1.EncryptedContent). Only supported for DMs (CONTACT_DM or DM); // always false for group chats. A private group is always end-to-end @@ -265,6 +294,25 @@ message MentionSuggestion { google.protobuf.Timestamp last_sent_at = 2; } +// SampledChatter is one member of a group in a sample of its chatters, as +// returned by Chat.SampleChatters: a member as of the read. It is not a +// Member message, carrying no join time or roster version, because a sample +// is a snapshot replaced whole rather than merged against the roster by +// version. +message SampledChatter { + // The member's public profile. + profile.v1.UserProfile user_profile = 1 [(validate.rules).message.required = true]; + + // When the member last sent a message in this chat, as the server records + // it: it may trail their latest message by up to a minute. A client + // moving new senders to the front compares against it. Unset for a + // creator who has not sent recently. + google.protobuf.Timestamp last_sent_at = 2; + + // Whether the member is the group's creator. + bool is_creator = 3; +} + // RosterSummary describes a chat's roster — its member list — without // containing it: what a client needs in order to know whether its copy of // that list is stale, without holding the list. @@ -298,12 +346,13 @@ message MetadataUpdate { oneof kind { option (validate.required) = true; - FullRefresh full_refresh = 1; - LastActivityChanged last_activity_changed = 2; - ViewerStateChanged viewer_state_changed = 3; - TitleChanged title_changed = 4; - PictureChanged picture_changed = 5; - DescriptionChanged description_changed = 6; + FullRefresh full_refresh = 1; + LastActivityChanged last_activity_changed = 2; + ViewerStateChanged viewer_state_changed = 3; + TitleChanged title_changed = 4; + ProfilePictureChanged profile_picture_changed = 5; + DescriptionChanged description_changed = 6; + CoverPictureChanged cover_picture_changed = 7; } // Refreshes the entire chat metadata @@ -333,14 +382,14 @@ message MetadataUpdate { }]; } - // The chat's picture has changed (e.g. via Chat.EditChat). Delivered to - // the chat's members, including the editor's other devices. Best-effort - // and applied as received; a client that suspects a miss refetches the - // chat via Chat.GetChat. - message PictureChanged { - // The new picture, with the renditions the server derived, replacing - // Metadata.picture. - blob.v1.Media new_picture = 1 [(validate.rules).message.required = true]; + // The chat's profile picture has changed (e.g. via Chat.EditChat). + // Delivered to the chat's members, including the editor's other devices. + // Best-effort and applied as received; a client that suspects a miss + // refetches the chat via Chat.GetChat. + message ProfilePictureChanged { + // The new profile picture, with the renditions the server derived, + // replacing Metadata.profile_picture. + blob.v1.Media new_profile_picture = 1 [(validate.rules).message.required = true]; } // The chat's description has changed (e.g. via Chat.EditChat). Delivered @@ -354,12 +403,24 @@ message MetadataUpdate { max_len: 160 }]; } + + // The chat's cover picture has changed (e.g. via Chat.EditChat). Delivered + // to the chat's members, including the editor's other devices. + // Best-effort and applied as received; a client that suspects a miss + // refetches the chat via Chat.GetChat. + message CoverPictureChanged { + // The new cover picture, with the renditions the server derived, + // replacing Metadata.cover_picture. + blob.v1.Media new_cover_picture = 1 [(validate.rules).message.required = true]; + } } // RosterUpdate is a best-effort, real-time change to a chat's roster — a // member joining (e.g. via Chat.JoinChat, or as the first member via -// Chat.StartChat) or leaving (e.g. via Chat.LeaveChat). It is delivered to -// the chat's members, including the affected user's other devices. +// Chat.StartChat) or leaving (e.g. via Chat.LeaveChat), or a change the +// recipient is not shown, which carries the summary alone (see +// MembershipChanged). It is delivered to the chat's members, including the +// affected user's other devices. // // Roster changes are a convergent overlay, so these ride the event stream // OUTSIDE the gap-detected event log. Clients apply them by roster_summary @@ -372,8 +433,9 @@ message RosterUpdate { oneof kind { option (validate.required) = true; - MemberJoined member_joined = 1; - MemberLeft member_left = 2; + MemberJoined member_joined = 1; + MemberLeft member_left = 2; + MembershipChanged membership_changed = 3; } // The chat's roster summary after this change, applied by version as @@ -407,6 +469,18 @@ message RosterUpdate { // The user that left common.v1.UserId user_id = 1 [(validate.rules).message.required = true]; } + + // The roster changed, but the change is not disclosed to the recipient: + // the update names no member and carries no member to add or remove. The + // recipient applies the enclosing roster_summary by version like any + // other roster update, so member_count and version stay current, and + // leaves its cached member list as it is. Having applied it, the + // recipient holds the new version, so it is not a version to reconcile + // by refetching the roster. + // + // It is never delivered to the user whose membership changed: their own + // devices receive MemberJoined or MemberLeft for it. + message MembershipChanged {} } message RosterUpdateBatch { @@ -617,8 +691,8 @@ message LobbyMember { // as returned by Chat.EnterLobby. message Lobby { // The chat, as a user who is not a member sees it: its record (title, - // picture, roster summary, creator) with in_lobby set, and none of its - // members or messaging state. + // profile picture, roster summary, creator) with in_lobby set, and none of + // its members or messaging state. Metadata chat = 1 [(validate.rules).message.required = true]; // When the user entered the lobby. From 7765668c8ddf78a10066a43ade273e794eb6f39b Mon Sep 17 00:00:00 2001 From: Brandon McAnsh Date: Tue, 6 Oct 2026 12:42:52 -0400 Subject: [PATCH 2/2] docs(changelog): describe 0.18.0 --- CHANGELOG.md | 66 +++++++++++++++++++ .../ContractInfo.swift | 2 +- 2 files changed, 67 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7116587..821a3a4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,72 @@ called out explicitly even when nothing else did. release notes, so a version with no entry here does not release. Write the entry in the same PR that syncs the contract, while the diff is still in front of you. +## 0.18.0 + +Synced to [`flipcash2-protobuf-api@9d44350b`](https://github.com/code-payments/flipcash2-protobuf-api/commit/9d44350b8d4d8eda9d63cff405238bd0e2920409), +picking up [#135](https://github.com/code-payments/flipcash2-protobuf-api/pull/135), +[#136](https://github.com/code-payments/flipcash2-protobuf-api/pull/136), +[#137](https://github.com/code-payments/flipcash2-protobuf-api/pull/137) and +[#138](https://github.com/code-payments/flipcash2-protobuf-api/pull/138). Only `chat.v1` moved; +`blob.v1` changed only in comments. + +### Renumbered + +- `EditChatResponse.Result`: `COVER_PICTURE_BLOB_NOT_ACCEPTED` is inserted at 5, and + `DESCRIPTION_MODERATED` moves from 5 to 6. 0.17.0 shipped `DESCRIPTION_MODERATED = 5`, so a + 0.17.0 client reads a cover-picture rejection from a current server as a moderated description, + and does not recognize 6 at all. Code that maps this enum by raw value, such as iOS's + `Error*(rawValue:)`, has to be re-checked case by case, not only extended. + +No other field or enum moved. `StartChatResponse.Result` gains its new case at the end. + +### Renamed + +The group picture becomes the profile picture, to tell it apart from the new cover picture. Field +numbers are unchanged, so this is wire-compatible but breaks source in both languages. + +- `Metadata.picture` → `profile_picture` (= 9). +- `picture` → `profile_picture` (= 2) on `PublicGroupChatParameters` and + `PrivateGroupChatParameters`. +- `EditChatRequest.picture` → `profile_picture` (= 3), and its type `Picture` → `ProfilePicture`. +- `MetadataUpdate.picture_changed` → `profile_picture_changed` (= 5), and `PictureChanged` → + `ProfilePictureChanged` with `new_picture` → `new_profile_picture`. +- `PICTURE_BLOB_NOT_ACCEPTED` → `PROFILE_PICTURE_BLOB_NOT_ACCEPTED` on `StartChatResponse.Result` + (= 3) and `EditChatResponse.Result` (= 4). + +### Added + +- Group cover pictures, the banner behind a chat's profile view. + - `Metadata.cover_picture` (= 17). The feed RPCs may leave it unset even when one is set, so a + feed result must not clear a cover picture the client already holds; `GetChat` returns it. + - Set at creation through `cover_picture` on `PublicGroupChatParameters` (= 5) and + `PrivateGroupChatParameters` (= 4), and changed through `EditChatRequest.cover_picture` + (= 5, a `CoverPicture { blob_id }` wrapper). + - Announced as `MetadataUpdate.CoverPictureChanged` (= 7, `new_cover_picture`). + - `COVER_PICTURE_BLOB_NOT_ACCEPTED` on `StartChatResponse.Result` (= 7) and + `EditChatResponse.Result` (= 5, see above). +- `RosterUpdate.MembershipChanged` (= 3), an empty case for a roster change the recipient is not + shown. Apply its `roster_summary` by version and leave the cached member list alone. +- `Chat.SampleChatters`, a public sample of up to 100 members of a public group: its creator, then + the most recent senders. Auth is optional. Returns `SampledChatter` (`user_profile`, + `last_sent_at`, `is_creator`) and `has_more`. +- `Chat.SetFeaturedGroups` and `Chat.GetFeaturedGroups`, an ordered list of up to 10 public groups a + user shows on their profile. `GetFeaturedGroups` looks the user up by `username`, takes optional + auth, and returns each group as a list view shows it, without `cover_picture` or any viewer or + messaging state. + +### Changed behavior + +- `GetRoster` now requires membership. A non-member whom a group's listener rules let read its + messages used to get the roster and now gets `DENIED`. `SampleChatters` is the public + alternative. + +### Upgrading + +Expect compile errors from the renames. Beyond those, an exhaustive `MetadataUpdate` switch needs +`CoverPictureChanged`, an exhaustive `RosterUpdate` switch needs `MembershipChanged`, and anything +that calls `GetRoster` for a group the user has not joined needs to stop. + ## 0.17.0 Synced to [`flipcash2-protobuf-api@3bb442d3`](https://github.com/code-payments/flipcash2-protobuf-api/commit/3bb442d359dd8452b4e3eca5f5c1ca463e7f5a4b), diff --git a/Sources/Flipcash2ClientProtocol/ContractInfo.swift b/Sources/Flipcash2ClientProtocol/ContractInfo.swift index 52aec29..5873174 100644 --- a/Sources/Flipcash2ClientProtocol/ContractInfo.swift +++ b/Sources/Flipcash2ClientProtocol/ContractInfo.swift @@ -1,7 +1,7 @@ // Generated by scripts/generate-swift.sh. Do not edit. public enum Flipcash2ContractInfo { - public static let version = "0.17.0-dev" + public static let version = "0.18.0-dev" public static let protoCommit = "9d44350b8d4d8eda9d63cff405238bd0e2920409" public static var isLocal: Bool { protoCommit == localSentinel }