
Език 🇧🇬 Български
Документация
Първи стъпки
Аутентификация
Използване
Add Comments to Your iOS App
Това е официалната iOS библиотека за FastComments.
Вградете живи коментари, чат и уиджети за ревюта в iOS приложението си.
Репозитория
Функции 
- Разклонени дървета от коментари с вложени отговори и пагинация
- Социална емисия със създаване на публикации, реакции и прикачени медии
- Режим на жив чат с автоматично превъртане и разделители за дати
- Актуализации в реално време чрез WebSocket (нови коментари, гласове, присъствие)
- Еднократно влизане (Simple SSO за тестване, Secure SSO за продукция)
- Редактиране на богато форматиран текст с удебелен, курсив, код и @споменавания
- Гласуване с конфигурируеми стилове (стрелки нагоре/надолу или сърца)
- Модераторски действия: маркиране, закрепване, заключване, блокиране
- Разширено тематизиране с предварително зададени стилове и пълна персонализация
- Персонализирани бутони в лентата с инструменти за коментари и създаване на публикации в емисията
- Качване на изображения
- Поддръжка за региона на ЕС
- Присъствие на потребители (индикатори за онлайн/офлайн)
- Филтриране на емисията по етикети
- Поддръжка за локализация
Инсталиране 
Добавете FastCommentsUI към вашия проект, като използвате Swift Package Manager.
В Xcode: File > Add Package Dependencies, след това въведете URL адреса на репозиторията.
Или го добавете във вашия Package.swift:
dependencies: [
.package(url: "https://github.com/fastcomments/fastcomments-ios.git", from: "1.0.0")
]
След това добавете продукта към вашата цел:
.target(
name: "YourApp",
dependencies: [
.product(name: "FastCommentsUI", package: "fastcomments-ios")
]
)
Импортирайте и двата модула, където е необходимо:
import FastCommentsUI
import FastCommentsSwift
Бърз старт 
Минималната настройка за показване на коментарен уиджет:
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()
}
}
}
Заменете "demo" с вашия FastComments tenant ID. urlId идентифицира страницата или нишката, където се съхраняват коментарите.
Аутентификация (SSO) 
FastComments поддържа три режима на удостоверяване:
- Анонимен -- няма SSO токен; потребителите получават идентичности, базирани на сесия
- Simple SSO -- клиентски токен за демота и тестове (не е сигурно)
- Secure SSO -- сървърно-подписан токен за продукция
Simple SSO
Подходящ за демота и локални тестове. Всеки може да се представи като всеки потребител със Simple SSO, затова не го използвайте в продукция.
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 също така поддържа опционални полета:
id-- потребителско ID (по подразбиране е email, ако не е зададено)displayName-- отделно показвано имеdisplayLabel-- персонализиран етикет, показван до името (например "VIP")websiteUrl-- връзка към името на потребителяlocale-- код на локалаisProfileActivityPrivate-- скриване на активността от профила (по подразбиране true)
Secure SSO
В продукция вашият бекенд генерира подписан SSO токен, използвайки вашия API секрет. iOS приложението извлича този токен от вашия сървър и го подава към конфигурацията.
On your backend (using the FastComments Swift SDK or any language):
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()
// Върнете този токен на вашето iOS приложение чрез вашето API
In your 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 {
// Извлечете токена от вашия бекенд
let token = try? await fetchSSOTokenFromYourBackend()
// Създайте нова конфигурация с токена, или го задайте преди зареждане
isLoadingToken = false
try? await sdk.load()
}
}
}
SecureSSOUserData поддържа допълнителни полета:
optedInNotifications-- съгласие за имейл известияdisplayLabel-- персонализиран етикетdisplayName-- показвано имеwebsiteUrl-- URL на уебсайтgroupIds-- членства в групиisAdmin-- администраторски привилегииisModerator-- модераторски привилегииisProfileActivityPrivate-- поверителност на профилната активност
Коментари в нишки 
Основно използване
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()
}
}
}
Стилове гласуване
По подразбиране стилът за гласуване показва стрелки нагоре/надолу. Използвайте ._1 за стил гласуване със сърце:
FastCommentsView(sdk: sdk, voteStyle: ._1)
| Стил | Външен вид |
|---|---|
._0 |
Бутони със стрелки нагоре/надолу с нетен брой |
._1 |
Един бутон със сърце и брой |
Обратни повиквания за събития
Използвайте модификаторни callback-и за обработка на потребителските взаимодействия:
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 е .name или .avatar
print("Tapped \(userInfo.displayName)")
}
Прилагане на тема
Подайте тема чрез SwiftUI средата:
FastCommentsView(sdk: sdk)
.fastCommentsTheme(myTheme)
.task { try? await sdk.load() }
Или я задайте директно в SDK:
sdk.theme = FastCommentsTheme.modern
Посока на сортиране
sdk.defaultSortDirection = .nf // Най-нови първи (по подразбиране)
sdk.defaultSortDirection = .of // Най-стари първи
sdk.defaultSortDirection = .mr // Най-релевантни
Чат на живо 
LiveChatView предоставя чат в реално време с автоматично превъртане, разделители по дати и компактен изглед. Той автоматично конфигурира SDK за сортиране от най-старите към най-новите и незабавно показване на живо.
struct ChatView: View {
@StateObject private var sdk: FastCommentsSDK = {
let config = FastCommentsWidgetConfig(
tenantId: "YOUR_TENANT_ID",
urlId: "chat-room-1",
sso: ssoToken // Препоръчва се SSO, за да имат потребителите имена
)
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-- извиква се, когато потребителят изпрати съобщение.onCommentDeleted-- извиква се, когато съобщение бъде изтрито.onUserClick-- извиква се, когато името или аватарът на потребител бъде докоснат
Социална емисия 
Системата за емисии е отделен SDK (FastCommentsFeedSDK) с собствен изглед.
Зареждане и показване на емисията
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
// Покажете лист за споделяне
}
.onUserClick { context, userInfo, source in
// Навигирайте към потребителския профил
}
.onMediaClick { mediaItem, index in
// Покажете разглеждане на изображение на цял екран
}
.task {
try? await sdk.load()
}
}
}
Изгледът на емисията включва автоматично издърпване за опресняване и безкрайно превъртане.
Създаване на публикации
Използвайте FeedPostCreateView, за да покажете формуляр за създаване на публикация:
@State private var showCreatePost = false
// В тялото на вашия изглед:
.sheet(isPresented: $showCreatePost) {
FeedPostCreateView(
sdk: sdk,
onPostCreated: { post in
showCreatePost = false
Task { try? await sdk.refresh() }
},
onCancelled: {
showCreatePost = false
}
)
}
Реакции към публикации
SDK-а обработва реакциите с оптимистични актуализации:
try await sdk.reactPost(postId: post.id, reactionType: "l")
// Проверете състоянието на реакцията
let hasLiked = sdk.hasUserReacted(postId: post.id, reactType: "l")
let likeCount = sdk.getLikeCount(postId: post.id)
Отваряне на коментари за публикация
Използвайте CommentsSheet, за да покажете коментарите за публикация в емисията. Той създава вътрешно екземпляр на FastCommentsSDK, като използва конфигурацията на feed SDK-а:
.sheet(item: $commentsPost) { post in
CommentsSheet(post: post, feedSDK: sdk, onUserClick: { context, userInfo, source in
// Обработете клик върху потребител
})
}
Забележка: FeedPost трябва да съответства на Identifiable, за да може да се използва .sheet(item:). Добавете това разширение:
extension FeedPost: @retroactive Identifiable {}
Филтриране на емисията по тагове
Имплементирайте протокола TagSupplier, за да филтрирате публикациите в емисията по тагове:
struct TeamTagSupplier: TagSupplier {
func getTags(currentUser: UserSessionInfo?) -> [String]? {
guard let user = currentUser else { return nil }
return ["team:\(user.id ?? "")", "public"]
}
}
sdk.tagSupplier = TeamTagSupplier()
Върнете nil за нефилтрирана глобална емисия.
Запазване и възстановяване на състоянието на емисията
Запазете състоянието на страниране между събитията от жизнения цикъл на изгледа:
let state = sdk.savePaginationState()
// Later...
sdk.restorePaginationState(state)
Изтриване на публикации
sdk.onPostDeleted = { postId in
print("Post \(postId) was deleted")
}
Персонализиране на тема 
Предварителни настройки на тема
Налични са четири вградени предварителни настройки:
// Системни настройки по подразбиране
sdk.theme = FastCommentsTheme.default
// Карти с сенки и големи заоблени ъгли
sdk.theme = FastCommentsTheme.modern
// Плосък, без сенки, малък радиус на ъглите, без линии на нишката
sdk.theme = FastCommentsTheme.minimal
// Задава всички цветове за действията като един брандов цвят
sdk.theme = FastCommentsTheme.allPrimary(.indigo)
Стилове на показване на коментари
var theme = FastCommentsTheme()
theme.commentStyle = .flat // Плосък списък с разделители (по подразбиране)
theme.commentStyle = .card // Заоблени карти със сенки
theme.commentStyle = .bubble // Стил тип чат балон
Цветове
Всички цветови свойства са незадължителни. Непопълнените стойности се връщат към разумни системни стойности по подразбиране.
var theme = FastCommentsTheme()
// Бранд цветове
theme.primaryColor = .indigo
theme.primaryLightColor = .indigo.opacity(0.6)
theme.primaryDarkColor = Color(red: 0.2, green: 0.1, blue: 0.5)
// Фонове
theme.commentBackgroundColor = Color(.secondarySystemGroupedBackground)
theme.containerBackgroundColor = Color(.systemGroupedBackground)
// Бутони за действие
theme.actionButtonColor = .indigo
theme.replyButtonColor = .indigo
theme.toggleRepliesButtonColor = .indigo.opacity(0.8)
theme.loadMoreButtonTextColor = .indigo
// Гласувания
theme.voteActiveColor = .red
theme.voteCountColor = .primary
theme.voteCountZeroColor = .secondary
theme.voteDividerColor = Color(.separator)
// Връзки
theme.linkColor = .indigo
theme.linkColorPressed = .indigo.opacity(0.5)
// Диалози
theme.dialogHeaderBackgroundColor = .indigo
theme.dialogHeaderTextColor = .white
// Лента за въвеждане
theme.inputBarBackgroundColor = Color(.systemBackground)
theme.inputBarBorderColor = Color(.separator)
// Други
theme.onlineIndicatorColor = .green
theme.separatorColor = Color(.separator)
theme.badgeBackgroundColor = .gray.opacity(0.2)
theme.threadLineColor = .indigo.opacity(0.15)
Типография
theme.commenterNameFont = .subheadline.weight(.bold)
theme.bodyFont = .body
theme.captionFont = .caption
theme.actionFont = .caption.weight(.medium)
Оформление и разстояния
theme.cornerRadius = .large // .none, .small, .medium, .large
theme.commentSpacing = 4 // Точки между редовете с коментари
theme.nestingIndent = 20 // Отместване (в точки) за всяко ниво на вложеност
theme.avatarSize = 36 // Диаметър на аватара за кореновите коментари
theme.replyAvatarSize = 28 // Диаметър на аватара за вложени отговори
Визуални ефекти
theme.showShadows = true // Нежни сенки върху картите
theme.showThreadLine = true // Вертикална линия свързваща вложените отговори
theme.animateVotes = true // Пружинна анимация при промяна на гласовете
Прилагане на теми
Два подхода:
// Чрез средата на SwiftUI (препоръчително за йерархията на изгледите)
FastCommentsView(sdk: sdk)
.fastCommentsTheme(theme)
// Директно в SDK
sdk.theme = theme
Персонализирани бутони в лентата с инструменти 
Бутони в лентата с инструменти за коментари
Имплементирайте протокола CustomToolbarButton, за да добавите бутони в лентата с инструменти за въвеждане на коментари:
struct EmojiButton: CustomToolbarButton {
let id = "emoji"
let iconSystemName = "face.smiling" // Име на SF Symbol
let contentDescription = "Add Emoji"
let badgeText: String? = nil // Опционален брой за значка
func onClick(text: Binding<String>) {
text.wrappedValue += "\u{1F44D}"
}
// Optional overrides (default to true)
func isEnabled() -> Bool { true }
func isVisible() -> Bool { true }
}
Подайте персонализирани бутони при създаване на изгледа:
FastCommentsView(
sdk: sdk,
customToolbarButtons: [EmojiButton(), CodeBlockButton()]
)
Или ги добавете глобално в SDK (важи за всички инстанции):
sdk.addGlobalCustomToolbarButton(EmojiButton())
sdk.removeGlobalCustomToolbarButton(id: "emoji")
sdk.clearGlobalCustomToolbarButtons()
Бутони в лентата с инструменти за емисията
Имплементирайте FeedCustomToolbarButton за формата за създаване на публикация:
struct HashtagButton: FeedCustomToolbarButton {
let id = "hashtag"
let iconSystemName = "number"
let contentDescription = "Add Hashtag"
func onClick(content: Binding<String>) {
content.wrappedValue += "#"
}
}
Подайте ги в изгледа за създаване:
FeedPostCreateView(
sdk: sdk,
customToolbarButtons: [HashtagButton()],
onPostCreated: { _ in },
onCancelled: { }
)
Или ги задайте глобално в feed SDK:
sdk.globalFeedToolbarButtons = [HashtagButton()]
Модерация 
Действия, достъпни за всички потребители
- Поставяне/Премахване на флаг -- докладване на коментар за преглед
try await sdk.flagComment(commentId: commentId)
try await sdk.unflagComment(commentId: commentId)
- Блокиране/Разблокиране -- скриване на всички коментари от потребител (за текущия зрител)
try await sdk.blockUser(commentId: commentId)
try await sdk.unblockUser(commentId: commentId)
Действия само за администратори
- Прикрепване/Откачване -- прикрепяне на коментар в горната част на нишката
try await sdk.pinComment(commentId: commentId)
try await sdk.unpinComment(commentId: commentId)
- Заключване/Отключване -- предотвратяване на нови отговори на коментар
try await sdk.lockComment(commentId: commentId)
try await sdk.unlockComment(commentId: commentId)
Всички модерационни действия са налични и чрез контекстното меню на коментара в потребителския интерфейс. Администраторските действия се показват само когато текущият потребител е администратор на сайта (зададено чрез SSO флага isAdmin или конфигурация в таблото за управление).
Актуализации в реално време 
След извикване на sdk.load(), SDK автоматично се абонира за WebSocket събития за конфигурирания urlId. Следните събития се обработват:
- Нови коментари, редакции и изтривания
- Гласувания (нови и премахнати)
- Промени в състоянието на закрепване, заключване, маркиране и блокиране
- Присъствие на потребители (влизане/напускане)
- Отваряне/затваряне на нишки
- Присъждане на значки
- Актуализации на конфигурацията на сървъра
Управление на живото показване
По подразбиране новите коментари от други потребители се появяват веднага:
sdk.showLiveRightAway = true // По подразбиране: показва се веднага
Задайте това на false, за да буферирате новите коментари зад бутон "N нови коментара", позволявайки на потребителя да избере кога да ги разкрие:
sdk.showLiveRightAway = false
Присъствие на потребителите
Индикаторите за онлайн/офлайн се появяват автоматично върху аватарите на потребителите, когато сървърът активира проследяването на присъствията. Не е необходима допълнителна конфигурация на клиента.
Пагинация 
Размер на страницата
// Коментари: по подразбиране 30
sdk.pageSize = 50
// Фийд: по подразбиране 10
feedSDK.pageSize = 20
Зареждане на още коментари
Потребителският интерфейс автоматично показва контролите за странициране. Можете също да задействате странициране програмно:
// Зареди следващата страница
try await sdk.loadMore()
// Зареди всички останали (деактивирано ако има >2000 коментара поради производителност)
try await sdk.loadAll()
// Проверка на състоянието
sdk.hasMore // Дали има още страници
sdk.shouldShowLoadAll()
sdk.getCountRemainingToShow()
Странициране на вложени коментари
Вложените отговори се зареждат лениво. Когато потребителят разшири нишка, първите 5 вложени отговора се зареждат. Ако има още, се появява контрол "зареди още отговори". Това се обработва автоматично от потребителския интерфейс.
Състояние и наблюдаемост 
И двете FastCommentsSDK и FastCommentsFeedSDK са класове ObservableObject с свойства @Published. Можете да наблюдавате тези свойства във вашите SwiftUI изгледи за реактивни актуализации на потребителския интерфейс.
Публикувани свойства на FastCommentsSDK
| Свойство | Тип | Описание |
|---|---|---|
commentCountOnServer |
Int |
Общ брой коментари на сървъра |
newRootCommentCount |
Int |
Буферирани нови коментари (когато showLiveRightAway е false) |
currentUser |
UserSessionInfo? |
Текущ удостоверен потребител |
isSiteAdmin |
Bool |
Дали текущият потребител е администратор на сайта |
isClosed |
Bool |
Дали нишката с коментари е затворена |
hasBillingIssue |
Bool |
Има ли проблем с фактурирането |
isLoading |
Bool |
Дали се изпълнява мрежова заявка |
hasMore |
Bool |
Има ли още страници с коментари |
blockingErrorMessage |
String? |
Грешка, която предотвратява функционирането на потребителския интерфейс |
warningMessage |
String? |
Неблокиращо предупредително съобщение |
isDemo |
Bool |
Дали работи в демонстрационен режим |
commentsVisible |
Bool |
Превключвател за видимостта на коментарите |
toolbarEnabled |
Bool |
Дали панелът за форматиране е показан |
Публикувани свойства на FastCommentsFeedSDK
| Свойство | Тип | Описание |
|---|---|---|
feedPosts |
[FeedPost] |
В момента заредени публикации във фийда |
hasMore |
Bool |
Има ли още страници |
currentUser |
UserSessionInfo? |
Текущ удостоверен потребител |
blockingErrorMessage |
String? |
Блокиращо съобщение за грешка |
isLoading |
Bool |
Дали се изпълнява мрежова заявка |
newPostsCount |
Int |
Брой нови публикации от последното зареждане |
Дървото на коментарите
Дървото на коментарите е достъпно чрез sdk.commentsTree:
// Плосък списък с видимите възли за рендиране
sdk.commentsTree.visibleNodes
// Намиране на коментар по ID
sdk.commentsTree.commentsById["comment-id"]
Регион на ЕС 
За да използвате центъра за данни в ЕС, задайте полето region във вашата конфигурация:
let config = FastCommentsWidgetConfig(
tenantId: "YOUR_TENANT_ID",
urlId: "my-page",
region: "eu"
)
Това насочва всички API заявки и WebSocket връзки към eu.fastcomments.com.
Почистване 
Когато приключите с екземпляр на SDK (например когато изгледът се затваря), извикайте cleanup(), за да затворите WebSocket връзката и да отмените фоновите задачи:
sdk.cleanup()
За изгледи, управлявани от SwiftUI чрез @StateObject, това обикновено се извиква в .onDisappear или когато изгледът бъде освободен от паметта.
Качване на изображения 
Коментари
let imageUrl = try await sdk.uploadImage(imageData: jpegData, filename: "photo.jpg")
Връща низ със URL адреса на каченото изображение.
Публикации в емисията
let mediaItem = try await feedSDK.uploadImage(imageData: jpegData, filename: "photo.jpg")
// Качване на няколко изображения паралелно
let mediaItems = try await feedSDK.uploadImages(images: [
(jpegData1, "photo1.jpg"),
(jpegData2, "photo2.jpg")
])
Споменавания на потребители 
Търсене на потребители за автоматичното довършване при @mention:
let results = try await sdk.searchUsers(query: "jan")
// Връща [UserSearchResult] с userId, username, avatar и т.н.
Вградената CommentInputBar се грижи за автоматичното довършване на @mention.
Редактиране и изтриване на коментари 
Редактиране
try await sdk.editComment(commentId: commentId, newText: "Updated text")
Сървърът рендерира HTML отново. Локалният коментар се актуализира автоматично.
Изтриване
try await sdk.deleteComment(commentId: commentId)
Изтриването на коментар също премахва неговите наследници от локалното дърво.
И двете действия са налични чрез контекстното меню на коментара в интерфейса, когато текущият потребител е авторът на коментара (или администратор на сайта).
Обработка на грешки 
Методите на SDK хвърлят FastCommentsError, който съответства на LocalizedError:
do {
try await sdk.load()
} catch let error as FastCommentsError {
print(error.translatedError ?? error.reason ?? "Unknown error")
} catch {
print(error.localizedDescription)
}
FastCommentsError свойства:
code-- код на грешка от API-тоreason-- описание на грешката на английскиtranslatedError-- локализирано съобщение за грешка, предоставено от сървъра
Blocking errors are also surfaced automatically via sdk.blockingErrorMessage, which the built-in views display to the user.
Локализация 
Предайте код на локал в конфигурацията, за да локализирате низовете, предоставени от сървъра:
let config = FastCommentsWidgetConfig(
tenantId: "YOUR_TENANT_ID",
urlId: "my-page",
locale: "fr_fr"
)
Низовете на потребителския интерфейс на клиентската страна използват локализация, базирана на iOS bundle.
Примерно приложение 
Хранилището съдържа пълно примерно приложение в ExampleApp/ с демонстрации на:
- Вложени коментари с SSO и персонализирани теми
- Социална емисия със създаване на публикации и филтриране по тагове
- Чат на живо
- Прости и сигурни SSO потоци
- Персонализирани бутони на лентата с инструменти (коментари и емисия)
Нужда от помощ?
Ако срещнете проблеми или имате въпроси относно iOS библиотеката, моля:
Принос
Приноси са добре дошли! Моля, посетете GitHub хранилището за указания относно приноса.