FastComments.com

Add Comments to Your iOS App

Dette er det officielle iOS-bibliotek for FastComments.

Integrer live-kommentarer, chat og anmeldelses-widgets i din iOS-app.

Arkiv

Se på GitHub


Funktioner Internal Link

  • Trådede kommentartræer med indlejrede svar og sideinddeling
  • Socialt feed med oprettelse af indlæg, reaktioner og medievedhæftninger
  • Live chat-tilstand med automatisk rulning og dataseparatorer
  • Realtidsopdateringer via WebSocket (nye kommentarer, stemmer, tilstedeværelse)
  • Single Sign-On (Simple SSO til test, Secure SSO til produktion)
  • Rig tekstredigering med fed, kursiv, kode og @mentions
  • Afstemning med konfigurerbare stilarter (op-/ned-pile eller hjerter)
  • Moderationshandlinger: marker, fastgør, lås, bloker
  • Omfattende temaindstillinger med forudindstillinger og fuld tilpasning
  • Egendefinerede værktøjslinjeknapper til kommentarer og oprettelse af feed-indlæg
  • Upload af billeder
  • Understøttelse af EU-regionen
  • Brugertilstedeværelse (online/offline-indikatorer)
  • Tag-baseret feedfiltrering
  • Understøttelse af lokalisering

Krav Internal Link


  • iOS 16+ eller macOS 14+
  • Swift 5.9+
  • SwiftUI

Installation Internal Link


Tilføj FastCommentsUI til dit projekt ved hjælp af Swift Package Manager.

I Xcode: Arkiv > Tilføj pakkeafhængigheder, indtast derefter repository-URL'en.

Eller tilføj det til din Package.swift:

dependencies: [
    .package(url: "https://github.com/fastcomments/fastcomments-ios.git", from: "1.0.0")
]

Then add the product to your target:

.target(
    name: "YourApp",
    dependencies: [
        .product(name: "FastCommentsUI", package: "fastcomments-ios")
    ]
)

Import both modules where needed:

import FastCommentsUI
import FastCommentsSwift

Hurtig start Internal Link


Den minimale opsætning for at vise en kommentar-widget:

import SwiftUI
import FastCommentsUI

struct ContentView: View {
    @StateObject private var sdk = FastCommentsSDK(
        config: FastCommentsWidgetConfig(
            tenantId: "demo",
            urlId: "my-page-1",
            url: "https://example.com/page-1",
            pageTitle: "My Page"
        )
    )

    var body: some View {
        FastCommentsView(sdk: sdk)
            .task {
                try? await sdk.load()
            }
    }
}

Udskift "demo" med dit FastComments tenant-id. urlId identificerer siden eller tråden, hvor kommentarerne gemmes.



Autentificering (SSO) Internal Link

FastComments understøtter tre autentificeringsmetoder:

  1. Anonym -- ingen SSO-token; brugere får sessionbaserede identiteter
  2. Simpel SSO -- klientside-token til demoer og test (ikke sikker)
  3. Sikker SSO -- serversigneret token til produktion

Simpel SSO

Brugbar til demoer og lokal testning. Alle kan udgive sig for en hvilken som helst bruger med Simpel SSO, så brug det ikke i produktion.

import FastCommentsSwift

let userData = SimpleSSOUserData(
    username: "Jane Doe",
    email: "jane@example.com",
    avatar: "https://example.com/avatar.jpg"
)
let sso = FastCommentsSSO.createSimple(simpleSSOUserData: userData)
let token = try? sso.prepareToSend()

let config = FastCommentsWidgetConfig(
    tenantId: "YOUR_TENANT_ID",
    urlId: "my-page-1",
    sso: token
)
let sdk = FastCommentsSDK(config: config)

SimpleSSOUserData understøtter også valgfrie felter:

  • id -- bruger-id (som standard e-mail hvis ikke angivet)
  • displayName -- separat visningsnavn
  • displayLabel -- brugerdefineret label vist ved siden af navnet (f.eks. "VIP")
  • websiteUrl -- link på brugerens navn
  • locale -- locale-kode
  • isProfileActivityPrivate -- skjuler profilaktivitet (som standard true)

Sikker SSO

I produktion genererer din backend et signerede SSO-token ved hjælp af din API-secret. iOS-appen henter dette token fra din server og sender det til konfigurationen.

På din backend (ved brug af FastComments Swift SDK eller ethvert sprog):

let userData = SecureSSOUserData(
    id: "user-123",
    email: "user@example.com",
    username: "Display Name",
    avatar: "https://example.com/avatar.jpg"
)
let sso = try FastCommentsSSO.createSecure(apiKey: "YOUR_API_KEY", secureSSOUserData: userData)
let token = try sso.prepareToSend()
// Return this token to your iOS app via your API

I din iOS-app:

struct MyView: View {
    @StateObject private var sdk = FastCommentsSDK(
        config: FastCommentsWidgetConfig(
            tenantId: "YOUR_TENANT_ID",
            urlId: "my-page-1"
        )
    )
    @State private var isLoadingToken = true

    var body: some View {
        Group {
            if isLoadingToken {
                ProgressView("Loading...")
            } else {
                FastCommentsView(sdk: sdk)
            }
        }
        .task {
            // Fetch the token from your backend
            let token = try? await fetchSSOTokenFromYourBackend()
            // Create a new config with the token, or set it before load
            isLoadingToken = false
            try? await sdk.load()
        }
    }
}

SecureSSOUserData understøtter yderligere felter:

  • optedInNotifications -- tilvalg af e-mailnotifikationer
  • displayLabel -- brugerdefineret label
  • displayName -- visningsnavn
  • websiteUrl -- webadresse
  • groupIds -- gruppe-medlemskaber
  • isAdmin -- administratorrettigheder
  • isModerator -- moderatorrettigheder
  • isProfileActivityPrivate -- profilens privatliv


Trådede kommentarer Internal Link

Grundlæggende brug

struct CommentsPage: View {
    @StateObject private var sdk = FastCommentsSDK(
        config: FastCommentsWidgetConfig(
            tenantId: "YOUR_TENANT_ID",
            urlId: "article-42",
            url: "https://example.com/article/42",
            pageTitle: "Article Title"
        )
    )

    var body: some View {
        FastCommentsView(sdk: sdk)
            .task {
                try? await sdk.load()
            }
    }
}

Stemmetyper

Standard stemmestil viser op-/ned-pile. Angiv ._1 for hjerte-stemmer:

FastCommentsView(sdk: sdk, voteStyle: ._1)
Stil Udseende
._0 Op-/ned-pileknapper med nettetal
._1 Enkel hjerteknap med antal

Hændelses-callbacks

Brug callbacks i modifier-stil til at håndtere brugerinteraktioner:

FastCommentsView(sdk: sdk)
    .onCommentPosted { comment in
        print("New comment: \(comment.commentHTML)")
    }
    .onReplyClick { renderableComment in
        print("Replying to: \(renderableComment.comment.id)")
    }
    .onUserClick { context, userInfo, source in
        // source er .name eller .avatar
        print("Tapped \(userInfo.displayName)")
    }

Anvend et tema

Angiv et tema via SwiftUI-miljøet:

FastCommentsView(sdk: sdk)
    .fastCommentsTheme(myTheme)
    .task { try? await sdk.load() }

Eller indstil det direkte på SDK'en:

sdk.theme = FastCommentsTheme.modern

Sorteringsretning

sdk.defaultSortDirection = .nf  // Nyeste først (standard)
sdk.defaultSortDirection = .of  // Ældste først
sdk.defaultSortDirection = .mr  // Mest relevante

Livechat Internal Link

LiveChatView giver en realtids chatoplevelse med automatisk rulning, datoseparatorer og et kompakt layout. Den konfigurerer SDK'en automatisk til ældste-først sortering og øjeblikkelig live-visning.

struct ChatView: View {
    @StateObject private var sdk: FastCommentsSDK = {
        let config = FastCommentsWidgetConfig(
            tenantId: "YOUR_TENANT_ID",
            urlId: "chat-room-1",
            sso: ssoToken  // SSO anbefales, så brugerne har navne
        )
        return FastCommentsSDK(config: config)
    }()

    var body: some View {
        LiveChatView(sdk: sdk)
            .onCommentPosted { comment in
                print("Sent: \(comment.commentHTML)")
            }
            .task {
                try? await sdk.load()
            }
    }
}

LiveChatView supports these callbacks:

  • .onCommentPosted -- udløses, når brugeren sender en besked
  • .onCommentDeleted -- udløses, når en besked slettes
  • .onUserClick -- udløses, når en brugers navn eller avatar trykkes på


Socialt feed Internal Link

Feed-systemet er et separat SDK (FastCommentsFeedSDK) med sin egen visning.

Indlæsning og visning af feedet

struct FeedPage: View {
    @StateObject private var sdk: FastCommentsFeedSDK = {
        let config = FastCommentsWidgetConfig(
            tenantId: "YOUR_TENANT_ID",
            urlId: "my-feed",
            sso: ssoToken
        )
        return FastCommentsFeedSDK(config: config)
    }()

    @State private var commentsPost: FeedPost?

    var body: some View {
        FastCommentsFeedView(sdk: sdk)
            .onPostSelected { post in
                commentsPost = post
            }
            .onCommentsRequested { post in
                commentsPost = post
            }
            .onSharePost { post in
                // Vis delingsark
            }
            .onUserClick { context, userInfo, source in
                // Naviger til brugerprofil
            }
            .onMediaClick { mediaItem, index in
                // Vis billedviser i fuld skærm
            }
            .task {
                try? await sdk.load()
            }
    }
}

Feed-visningen inkluderer pull-to-refresh og automatisk uendelig scroll.

Oprette indlæg

Brug FeedPostCreateView til at vise en formular til oprettelse af indlæg:

@State private var showCreatePost = false

// In your view body:
.sheet(isPresented: $showCreatePost) {
    FeedPostCreateView(
        sdk: sdk,
        onPostCreated: { post in
            showCreatePost = false
            Task { try? await sdk.refresh() }
        },
        onCancelled: {
            showCreatePost = false
        }
    )
}

Reagere på indlæg

SDK'en håndterer reaktioner med optimistiske opdateringer:

try await sdk.reactPost(postId: post.id, reactionType: "l")

// Check reaction state
let hasLiked = sdk.hasUserReacted(postId: post.id, reactType: "l")
let likeCount = sdk.getLikeCount(postId: post.id)

Åbne kommentarer for et indlæg

Brug CommentsSheet til at vise kommentarer for et feed-indlæg. Den opretter internt en FastCommentsSDK-instans ved hjælp af feed-SDK'ens konfiguration:

.sheet(item: $commentsPost) { post in
    CommentsSheet(post: post, feedSDK: sdk, onUserClick: { context, userInfo, source in
        // Håndter klik på bruger
    })
}

Bemærk: FeedPost skal overholde Identifiable for .sheet(item:). Tilføj denne extension:

extension FeedPost: @retroactive Identifiable {}

Tag-baseret filtrering af feed

Implementer TagSupplier-protokollen for at filtrere feed-indlæg efter tags:

struct TeamTagSupplier: TagSupplier {
    func getTags(currentUser: UserSessionInfo?) -> [String]? {
        guard let user = currentUser else { return nil }
        return ["team:\(user.id ?? "")", "public"]
    }
}

sdk.tagSupplier = TeamTagSupplier()

Returnér nil for et ufiltreret globalt feed.

Gemme og gendanne feed-tilstand

Bevar pagineringsstatus på tværs af visningens livscyklus-begivenheder:

let state = sdk.savePaginationState()
// Later...
sdk.restorePaginationState(state)

Slette indlæg

sdk.onPostDeleted = { postId in
    print("Post \(postId) was deleted")
}


Tema Internal Link

Tema-præindstillinger

Fire indbyggede præindstillinger er tilgængelige:

// Systemstandarder
sdk.theme = FastCommentsTheme.default

// Kort med skygger og store afrundede hjørner
sdk.theme = FastCommentsTheme.modern

// Fladt, ingen skygger, lille hjørneradius, ingen trådlinjer
sdk.theme = FastCommentsTheme.minimal

// Sæt alle handlingsfarver til en enkelt brandfarve
sdk.theme = FastCommentsTheme.allPrimary(.indigo)

Kommentarvisningsstilarter

var theme = FastCommentsTheme()
theme.commentStyle = .flat    // Flad liste med skillelinjer (standard)
theme.commentStyle = .card    // Afrundede kort med skygger
theme.commentStyle = .bubble  // Chatboble-stil

Farver

Alle farveegenskaber er valgfrie. Udefinerede værdier vender tilbage til fornuftige systemstandarder.

var theme = FastCommentsTheme()

// Brandfarver
theme.primaryColor = .indigo
theme.primaryLightColor = .indigo.opacity(0.6)
theme.primaryDarkColor = Color(red: 0.2, green: 0.1, blue: 0.5)

// Baggrunde
theme.commentBackgroundColor = Color(.secondarySystemGroupedBackground)
theme.containerBackgroundColor = Color(.systemGroupedBackground)

// Handlingsknapper
theme.actionButtonColor = .indigo
theme.replyButtonColor = .indigo
theme.toggleRepliesButtonColor = .indigo.opacity(0.8)
theme.loadMoreButtonTextColor = .indigo

// Stemmer
theme.voteActiveColor = .red
theme.voteCountColor = .primary
theme.voteCountZeroColor = .secondary
theme.voteDividerColor = Color(.separator)

// Links
theme.linkColor = .indigo
theme.linkColorPressed = .indigo.opacity(0.5)

// Dialoger
theme.dialogHeaderBackgroundColor = .indigo
theme.dialogHeaderTextColor = .white

// Indtastningsbjælke
theme.inputBarBackgroundColor = Color(.systemBackground)
theme.inputBarBorderColor = Color(.separator)

// Andre
theme.onlineIndicatorColor = .green
theme.separatorColor = Color(.separator)
theme.badgeBackgroundColor = .gray.opacity(0.2)
theme.threadLineColor = .indigo.opacity(0.15)

Typografi

theme.commenterNameFont = .subheadline.weight(.bold)
theme.bodyFont = .body
theme.captionFont = .caption
theme.actionFont = .caption.weight(.medium)

Layout og mellemrum

theme.cornerRadius = .large       // .none, .small, .medium, .large
theme.commentSpacing = 4          // Punkter mellem kommentarrækker
theme.nestingIndent = 20          // Antal punkter til indrykning pr. niveau
theme.avatarSize = 36             // Avatardiameter for topniveau-kommentarer
theme.replyAvatarSize = 28        // Avatardiameter for indlejrede svar

Visuelle effekter

theme.showShadows = true          // Diskrete skygger på kort
theme.showThreadLine = true       // Lodret linje, der forbinder indlejrede svar
theme.animateVotes = true         // Spring-animation ved stemmeændringer

Anvendelse af temaer

To tilgange:

// Via SwiftUI-miljøet (anbefales til visningshierarki)
FastCommentsView(sdk: sdk)
    .fastCommentsTheme(theme)

// Direkte på SDK'en
sdk.theme = theme


Brugerdefinerede knapper på værktøjslinjen Internal Link

Kommentarværktøjslinje-knapper

Implementer CustomToolbarButton-protokollen for at tilføje knapper til kommentarfeltets værktøjslinje:

struct EmojiButton: CustomToolbarButton {
    let id = "emoji"
    let iconSystemName = "face.smiling"       // SF Symbol-navn
    let contentDescription = "Add Emoji"
    let badgeText: String? = nil              // Valgfri badge-tæller

    func onClick(text: Binding<String>) {
        text.wrappedValue += "\u{1F44D}"
    }

    // Valgfrie overrides (standard er true)
    func isEnabled() -> Bool { true }
    func isVisible() -> Bool { true }
}

Videregiv brugerdefinerede knapper, når du opretter visningen:

FastCommentsView(
    sdk: sdk,
    customToolbarButtons: [EmojiButton(), CodeBlockButton()]
)

Eller tilføj dem globalt på SDK'et (gælder for alle forekomster):

sdk.addGlobalCustomToolbarButton(EmojiButton())
sdk.removeGlobalCustomToolbarButton(id: "emoji")
sdk.clearGlobalCustomToolbarButtons()

Feed-værktøjslinjeknapper

Implementer FeedCustomToolbarButton til indlægsoprettelsesformularen:

struct HashtagButton: FeedCustomToolbarButton {
    let id = "hashtag"
    let iconSystemName = "number"
    let contentDescription = "Add Hashtag"

    func onClick(content: Binding<String>) {
        content.wrappedValue += "#"
    }
}

Videregiv dem til oprettelsesvisningen:

FeedPostCreateView(
    sdk: sdk,
    customToolbarButtons: [HashtagButton()],
    onPostCreated: { _ in },
    onCancelled: { }
)

Eller indstil dem globalt på feed-SDK'et:

sdk.globalFeedToolbarButtons = [HashtagButton()]


Moderering Internal Link

Handlinger tilgængelige for alle brugere

  • Flag/Unflag -- anmeld en kommentar til gennemgang
try await sdk.flagComment(commentId: commentId)
try await sdk.unflagComment(commentId: commentId)
  • Block/Unblock -- skjul alle kommentarer fra en bruger (for hver enkelt seer)
try await sdk.blockUser(commentId: commentId)
try await sdk.unblockUser(commentId: commentId)

Handlinger kun for administratorer

  • Pin/Unpin -- fastgør en kommentar til toppen af tråden
try await sdk.pinComment(commentId: commentId)
try await sdk.unpinComment(commentId: commentId)
  • Lock/Unlock -- forhindre nye svar på en kommentar
try await sdk.lockComment(commentId: commentId)
try await sdk.unlockComment(commentId: commentId)

Alle moderationshandlinger er også tilgængelige gennem kommentarens kontekstmenu i brugergrænsefladen. Admin-handlinger vises kun, når den aktuelle bruger er site-admin (angivet via SSO isAdmin-flaget eller dashboard-konfiguration).


Opdateringer i realtid Internal Link

Efter at have kaldt sdk.load(), abonnerer SDK'en automatisk på WebSocket-begivenheder for den konfigurerede urlId. Følgende begivenheder håndteres:

  • Nye kommentarer, redigeringer og sletninger
  • Stemmer (nye og fjernede)
  • Ændringer i pin-, låse-, flag- og blokeringstilstande
  • Bruger-tilstedeværelse (tilslutning/forladelse)
  • Tråd åben/lukket
  • Tildeling af badges
  • Opdateringer af serverkonfigurationen

Styring af livevisning

Som standard vises nye kommentarer fra andre brugere med det samme:

sdk.showLiveRightAway = true   // Standard: vises med det samme

Sæt dette til false for at bufre nye kommentarer bag en "N nye kommentarer"-knap, så brugeren kan vælge, hvornår de skal vises:

sdk.showLiveRightAway = false

Bruger-tilstedeværelse

Online-/offlineindikatorer vises automatisk på brugeravatarer, når serveren aktiverer tilstedeværelsessporing. Der kræves ingen yderligere konfiguration på klienten.

Sideinddeling Internal Link

Sidestørrelse

// Kommentarer: standard 30
sdk.pageSize = 50

// Feed: standard 10
feedSDK.pageSize = 20

Indlæsning af flere kommentarer

Brugergrænsefladen viser pagineringskontroller automatisk. Du kan også udløse paginering programmatisk:

// Indlæs næste side
try await sdk.loadMore()

// Indlæs alle resterende (deaktiveret hvis >2000 kommentarer af hensyn til ydeevne)
try await sdk.loadAll()

// Kontroller status
sdk.hasMore            // Whether more pages exist
sdk.shouldShowLoadAll()
sdk.getCountRemainingToShow()

Paginering af underkommentarer

Indlejrede svar indlæses efter behov. Når en bruger udvider en tråd, indlæses de første 5 underkommentarer. En "indlæs flere svar"-kontrol vises, hvis der er flere. Dette håndteres automatisk af brugergrænsefladen.



Tilstand og observabilitet Internal Link

Både FastCommentsSDK og FastCommentsFeedSDK er ObservableObject-klasser med @Published-egenskaber. Du kan observere disse i dine SwiftUI-visninger for reaktive UI-opdateringer.

FastCommentsSDK Publicerede Egenskaber

Property Type Description
commentCountOnServer Int Samlet antal kommentarer på serveren
newRootCommentCount Int Bufferede nye kommentarer (når showLiveRightAway is false)
currentUser UserSessionInfo? Nuværende autentificerede bruger
isSiteAdmin Bool Om den aktuelle bruger er siteadministrator
isClosed Bool Om kommentertråden er lukket
hasBillingIssue Bool Om der er et betalingsproblem
isLoading Bool Om en netværksanmodning er i gang
hasMore Bool Om der findes flere sider med kommentarer
blockingErrorMessage String? Fejl, der forhindrer brugergrænsefladen i at fungere
warningMessage String? Ikke-blokerende advarselsmeddelelse
isDemo Bool Om der køres i demotilstand
commentsVisible Bool Om kommentarer er synlige
toolbarEnabled Bool Om formateringsværktøjslinjen vises

FastCommentsFeedSDK Publicerede Egenskaber

Property Type Description
feedPosts [FeedPost] Aktuelt indlæste feedindlæg
hasMore Bool Om der findes flere sider
currentUser UserSessionInfo? Nuværende autentificerede bruger
blockingErrorMessage String? Blokerende fejlmeddelelse
isLoading Bool Om en netværksanmodning er i gang
newPostsCount Int Antal nye indlæg siden sidste indlæsning

Kommentartræ

Kommentartræet kan tilgås via sdk.commentsTree:

// Flad liste over synlige noder til gengivelse
sdk.commentsTree.visibleNodes

// Find en kommentar efter ID
sdk.commentsTree.commentsById["comment-id"]


EU-region Internal Link


For at bruge EU-datacenteret skal du sætte feltet region i din konfiguration:

let config = FastCommentsWidgetConfig(
    tenantId: "YOUR_TENANT_ID",
    urlId: "my-page",
    region: "eu"
)

Dette dirigerer alle API-forespørgsler og WebSocket-forbindelser til eu.fastcomments.com.



Oprydning Internal Link


Når du er færdig med en SDK-instans (f.eks. når visningen lukkes), kald cleanup() for at lukke WebSocket-forbindelsen og annullere baggrundsopgaver:

sdk.cleanup()

For visninger styret af SwiftUI's @StateObject kaldes dette typisk i .onDisappear eller når visningen bliver deallokeret.



Upload af billeder Internal Link

Kommentarer

let imageUrl = try await sdk.uploadImage(imageData: jpegData, filename: "photo.jpg")

Returnerer URL-strengen for det uploadede billede.

Feed-indlæg

let mediaItem = try await feedSDK.uploadImage(imageData: jpegData, filename: "photo.jpg")

// Upload flere billeder parallelt
let mediaItems = try await feedSDK.uploadImages(images: [
    (jpegData1, "photo1.jpg"),
    (jpegData2, "photo2.jpg")
])


Brugernævnelser Internal Link


Søg efter brugere for at understøtte @mention-autofuldførelse:

let results = try await sdk.searchUsers(query: "jan")
// Returnerer [UserSearchResult] med userId, username, avatar osv.

Den indbyggede CommentInputBar håndterer @mention-autofuldførelse automatisk.



Redigering og sletning af kommentarer Internal Link


Rediger

try await sdk.editComment(commentId: commentId, newText: "Updated text")

Serveren renderer HTML'en igen. Den lokale kommentar opdateres automatisk.

Slet

try await sdk.deleteComment(commentId: commentId)

Sletning af en kommentar fjerner også dens efterkommere fra det lokale træ.

Begge handlinger er tilgængelige via kommentarens kontekstmenu i UI'en, når den aktuelle bruger er kommentarens forfatter (eller en webstedsadministrator).



Fejlhåndtering Internal Link

SDK-metoder kaster FastCommentsError, som overholder LocalizedError:

do {
    try await sdk.load()
} catch let error as FastCommentsError {
    print(error.translatedError ?? error.reason ?? "Unknown error")
} catch {
    print(error.localizedDescription)
}

FastCommentsError egenskaber:

  • code -- fejlkode fra API'en
  • reason -- engelsk fejlbeskrivelse
  • translatedError -- lokaliseret fejlmeddelelse leveret af serveren

Blokeringsfejl vises også automatisk via sdk.blockingErrorMessage, som de indbyggede visninger viser for brugeren.



Lokalisering Internal Link


Angiv en lokalekode i konfigurationen for at lokalisere server-leverede strenge:

let config = FastCommentsWidgetConfig(
    tenantId: "YOUR_TENANT_ID",
    urlId: "my-page",
    locale: "fr_fr"
)

Klientside UI-strenge bruger iOS bundle-baseret lokalisering.



Eksempelapp Internal Link


Dette repository indeholder en komplet eksempel-app i ExampleApp/ med demonstrationer af:

  • Trådede kommentarer med SSO og brugerdefinerede temaer
  • Socialt feed med oprettelse af opslag og filtrering efter tags
  • Live chat
  • Enkle og sikre SSO-forløb
  • Brugerdefinerede værktøjsknapper (kommentarer og feed)


Har du brug for hjælp?

Hvis du støder på problemer eller har spørgsmål om iOS-biblioteket, så:

Bidrag

Bidrag er velkomne! Besøg venligst GitHub-repositoriet for retningslinjer for bidrag.