~ knotless Search/
↑↓ move↵ open⇧↵ all results

grain.social/grain-ios

1 collaborator
0
1
main
142 lines · 4.5 KB Raw History
import Foundation

// Response types for profile-related XRPC queries.

struct GetFollowersResponse: Codable, Sendable {
    var totalCount: Int?
    var items: [FollowerItem]?
    var cursor: String?
}

struct GetFollowingResponse: Codable, Sendable {
    var totalCount: Int?
    var items: [FollowingItem]?
    var cursor: String?
}

struct GetKnownFollowersResponse: Codable, Sendable {
    var items: [FollowerItem]?
}

struct GetGalleryFavoritesResponse: Codable, Sendable {
    var totalCount: Int?
    var items: [FavoriteItem]?
    var cursor: String?
}

struct GetSuggestedFollowsResponse: Codable, Sendable {
    var items: [SuggestedItem]?
}

struct SearchProfilesResponse: Codable, Sendable {
    var items: [ProfileSearchResult]?
    var cursor: String?
}

struct FollowerItem: Codable, Sendable, Identifiable {
    let did: String
    var handle: String?
    var displayName: String?
    var description: String?
    var avatar: String?
    var viewer: ActorViewerState?
    var id: String {
        did
    }
}

struct FollowingItem: Codable, Sendable, Identifiable {
    let did: String
    var handle: String?
    var displayName: String?
    var description: String?
    var avatar: String?
    var viewer: ActorViewerState?
    var id: String {
        did
    }
}

struct FavoriteItem: Codable, Sendable, Identifiable {
    let did: String
    var handle: String?
    var displayName: String?
    var description: String?
    var avatar: String?
    var viewer: ActorViewerState?
    var id: String {
        did
    }
}

struct SuggestedItem: Codable, Sendable, Identifiable {
    let did: String
    var handle: String?
    var displayName: String?
    var description: String?
    var avatar: String?
    var followersCount: Int?
    var id: String {
        did
    }
}

struct ProfileSearchResult: Codable, Sendable, Identifiable {
    let did: String
    var handle: String?
    var displayName: String?
    var description: String?
    var avatar: String?
    var id: String {
        did
    }
}

// MARK: - Convenience Extensions

extension XRPCClient {
    func getActorProfile(actor: String, auth: AuthContext? = nil) async throws -> GrainProfileDetailed {
        try await query("social.grain.actor.getProfile", params: ["actor": actor], auth: auth, as: GrainProfileDetailed.self)
    }

    func getFollowers(actor: String, limit: Int = 50, cursor: String? = nil, auth: AuthContext? = nil) async throws -> GetFollowersResponse {
        var params = ["actor": actor, "limit": String(limit)]
        if let cursor {
            params["cursor"] = cursor
        }
        return try await query("social.grain.graph.getFollowers", params: params, auth: auth, as: GetFollowersResponse.self)
    }

    func getFollowing(actor: String, limit: Int = 50, cursor: String? = nil, auth: AuthContext? = nil) async throws -> GetFollowingResponse {
        var params = ["actor": actor, "limit": String(limit)]
        if let cursor {
            params["cursor"] = cursor
        }
        return try await query("social.grain.graph.getFollowing", params: params, auth: auth, as: GetFollowingResponse.self)
    }

    /// The accounts the signed-in viewer follows that follow `actor`.
    func getKnownFollowers(actor: String, auth: AuthContext? = nil) async throws -> GetKnownFollowersResponse {
        try await query("social.grain.graph.getKnownFollowers", params: ["actor": actor], auth: auth, as: GetKnownFollowersResponse.self)
    }

    func getGalleryFavorites(gallery: String, limit: Int = 50, cursor: String? = nil, auth: AuthContext? = nil) async throws -> GetGalleryFavoritesResponse {
        var params = ["gallery": gallery, "limit": String(limit)]
        if let cursor {
            params["cursor"] = cursor
        }
        return try await query("social.grain.gallery.getFavorites", params: params, auth: auth, as: GetGalleryFavoritesResponse.self)
    }

    func getSuggestedFollows(actor: String, limit: Int = 10, auth: AuthContext? = nil) async throws -> GetSuggestedFollowsResponse {
        try await query("social.grain.actor.getSuggestedFollows", params: ["actor": actor, "limit": String(limit)], auth: auth, as: GetSuggestedFollowsResponse.self)
    }

    func searchProfiles(query queryString: String, limit: Int = 30, cursor: String? = nil, auth: AuthContext? = nil) async throws -> SearchProfilesResponse {
        var params = ["q": queryString, "limit": String(limit)]
        if let cursor {
            params["cursor"] = cursor
        }
        return try await query("social.grain.actor.searchActors", params: params, auth: auth, as: SearchProfilesResponse.self)
    }
}