Skip to content

Commit a6e6918

Browse files
authored
feat: Header bar customization (#3)
1 parent 958b9a3 commit a6e6918

File tree

3 files changed

+15
-151
lines changed

3 files changed

+15
-151
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ To enable photo capture or image upload features in the chat interface, **you mu
7777
| `pubsubToken` | `String` || - | Token for real-time updates |
7878
| `websocketUrl` | `String` || - | WebSocket URL for real-time communication |
7979
| `inboxName` | `String` || - | Display name for the inbox/chat channel |
80+
| `inboxNameFontSize` | `CGFloat` || `18` | Font size for the inbox name in header |
8081
| `backArrowIcon` | `UIImage` || - | Back arrow icon for the header bar |
8182
| `connectedIcon` | `UIImage` || - | Icon displayed when the app is online |
8283
| `disconnectedIcon` | `UIImage` || - | Icon displayed when the app is offline |
@@ -102,6 +103,7 @@ ChatwootSDK.setup(ChatwootConfiguration(
102103
pubsubToken: "YOUR_PUBSUB_TOKEN",
103104
websocketUrl: "wss://your-chatwoot.com",
104105
inboxName: "Support", // Display name for the inbox
106+
inboxNameFontSize: 20, // Optional: font size for inbox name (default: 18)
105107
backArrowIcon: backArrowIcon, // Required: UIImage object
106108
connectedIcon: connectedIcon, // Required: UIImage object
107109
disconnectedIcon: disconnectedIcon, // Required: UIImage object

Sources/ChatwootSDK/ChatwootSDK.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ public struct ChatwootConfiguration {
1010
public let pubsubToken: String
1111
public let websocketUrl: String
1212
public let inboxName: String
13+
public let inboxNameFontSize: CGFloat
1314
public let disableEditor: Bool
1415
public let editorDisableUpload: Bool
1516
#if canImport(UIKit)
@@ -26,6 +27,7 @@ public struct ChatwootConfiguration {
2627
pubsubToken: String,
2728
websocketUrl: String,
2829
inboxName: String,
30+
inboxNameFontSize: CGFloat = 18,
2931
disableEditor: Bool = false,
3032
editorDisableUpload: Bool = false,
3133
backArrowIcon: UIImage,
@@ -38,6 +40,7 @@ public struct ChatwootConfiguration {
3840
self.pubsubToken = pubsubToken
3941
self.websocketUrl = websocketUrl
4042
self.inboxName = inboxName
43+
self.inboxNameFontSize = inboxNameFontSize
4144
self.disableEditor = disableEditor
4245
self.editorDisableUpload = editorDisableUpload
4346
self.backArrowIcon = backArrowIcon
@@ -52,6 +55,7 @@ public struct ChatwootConfiguration {
5255
pubsubToken: String,
5356
websocketUrl: String,
5457
inboxName: String,
58+
inboxNameFontSize: CGFloat = 18,
5559
disableEditor: Bool = false,
5660
editorDisableUpload: Bool = false
5761
) {
@@ -61,6 +65,7 @@ public struct ChatwootConfiguration {
6165
self.pubsubToken = pubsubToken
6266
self.websocketUrl = websocketUrl
6367
self.inboxName = inboxName
68+
self.inboxNameFontSize = inboxNameFontSize
6469
self.disableEditor = disableEditor
6570
self.editorDisableUpload = editorDisableUpload
6671
}

Sources/ChatwootSDK/ChatwootView.swift

Lines changed: 8 additions & 151 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,8 @@ public class ChatwootViewController: UIViewController {
2121
private var closeButton: UIButton!
2222
/// Header view for profile information
2323
private var headerView: UIView!
24-
/// Profile label
25-
private var profileLabel: UILabel!
2624
/// Inbox name label
2725
private var inboxLabel: UILabel!
28-
/// Avatar image view
29-
private var avatarImageView: UIImageView!
30-
/// Loading indicator
31-
private var loadingIndicator: UIActivityIndicatorView!
3226
/// Theme color for the view
3327
private var themeColor: UIColor = .white
3428
/// Connection status indicator
@@ -41,9 +35,6 @@ public class ChatwootViewController: UIViewController {
4135
private let networkQueue = DispatchQueue(label: "NetworkMonitor")
4236
#endif
4337

44-
/// Profile data
45-
private var profile: ChatwootProfile = ChatwootProfile(name: "Loading...")
46-
private var isProfileLoading: Bool = true
4738

4839
// Private class for bundle reference
4940
private class BundleClass {}
@@ -67,7 +58,6 @@ public class ChatwootViewController: UIViewController {
6758
public override func viewDidLoad() {
6859
super.viewDidLoad()
6960
setupUI()
70-
loadProfileData()
7161
loadWebView()
7262
setupNetworkMonitoring()
7363
}
@@ -113,40 +103,15 @@ public class ChatwootViewController: UIViewController {
113103
connectionStatusView.translatesAutoresizingMaskIntoConstraints = false
114104
headerView.addSubview(connectionStatusView)
115105

116-
// Create avatar image view
117-
avatarImageView = UIImageView()
118-
avatarImageView.contentMode = .scaleAspectFill
119-
avatarImageView.layer.cornerRadius = 16
120-
avatarImageView.layer.masksToBounds = true
121-
avatarImageView.backgroundColor = UIColor.blue.withAlphaComponent(0.2)
122-
avatarImageView.translatesAutoresizingMaskIntoConstraints = false
123-
headerView.addSubview(avatarImageView)
124-
125-
// Create profile label
126-
profileLabel = UILabel()
127-
profileLabel.font = UIFont.systemFont(ofSize: 18, weight: .semibold)
128-
profileLabel.textColor = contentColor // Use dynamic content color
129-
profileLabel.text = profile.name
130-
profileLabel.translatesAutoresizingMaskIntoConstraints = false
131-
headerView.addSubview(profileLabel)
132-
133-
// Create inbox label
106+
// Create inbox label
134107
inboxLabel = UILabel()
135-
inboxLabel.font = UIFont.systemFont(ofSize: 13, weight: .regular)
136-
inboxLabel.textColor = contentColor.withAlphaComponent(0.7) // Use dynamic content color with alpha
108+
inboxLabel.font = UIFont.systemFont(ofSize: configuration.inboxNameFontSize, weight: .semibold)
109+
inboxLabel.textColor = contentColor
137110
inboxLabel.text = configuration.inboxName
111+
inboxLabel.textAlignment = .center
138112
inboxLabel.translatesAutoresizingMaskIntoConstraints = false
139113
headerView.addSubview(inboxLabel)
140114

141-
// Create loading indicator
142-
if #available(iOS 13.0, *) {
143-
loadingIndicator = UIActivityIndicatorView(style: .medium)
144-
} else {
145-
loadingIndicator = UIActivityIndicatorView(style: .gray)
146-
}
147-
loadingIndicator.translatesAutoresizingMaskIntoConstraints = false
148-
avatarImageView.addSubview(loadingIndicator)
149-
150115
// Configure WebView
151116
let webConfiguration = WKWebViewConfiguration()
152117
webConfiguration.allowsInlineMediaPlayback = true
@@ -213,26 +178,10 @@ public class ChatwootViewController: UIViewController {
213178
connectionStatusView.widthAnchor.constraint(equalToConstant: 22),
214179
connectionStatusView.heightAnchor.constraint(equalToConstant: 22),
215180

216-
// Avatar constraints
217-
avatarImageView.leadingAnchor.constraint(equalTo: closeButton.trailingAnchor, constant: 12),
218-
avatarImageView.centerYAnchor.constraint(equalTo: headerView.centerYAnchor),
219-
avatarImageView.widthAnchor.constraint(equalToConstant: 32),
220-
avatarImageView.heightAnchor.constraint(equalToConstant: 32),
221-
222-
// Loading indicator constraints
223-
loadingIndicator.centerXAnchor.constraint(equalTo: avatarImageView.centerXAnchor),
224-
loadingIndicator.centerYAnchor.constraint(equalTo: avatarImageView.centerYAnchor),
225-
226-
// Profile label constraints
227-
profileLabel.leadingAnchor.constraint(equalTo: avatarImageView.trailingAnchor, constant: 12),
228-
profileLabel.topAnchor.constraint(equalTo: headerView.topAnchor, constant: 12),
229-
profileLabel.trailingAnchor.constraint(lessThanOrEqualTo: connectionStatusView.leadingAnchor, constant: -12),
230-
231-
// Inbox label constraints
232-
inboxLabel.leadingAnchor.constraint(equalTo: avatarImageView.trailingAnchor, constant: 12),
233-
inboxLabel.topAnchor.constraint(equalTo: profileLabel.bottomAnchor, constant: 2),
234-
inboxLabel.trailingAnchor.constraint(lessThanOrEqualTo: connectionStatusView.leadingAnchor, constant: -12),
235-
inboxLabel.bottomAnchor.constraint(lessThanOrEqualTo: headerView.bottomAnchor, constant: -12),
181+
// Inbox label constraints (centered between close button and connection status)
182+
inboxLabel.leadingAnchor.constraint(equalTo: closeButton.trailingAnchor, constant: 12),
183+
inboxLabel.trailingAnchor.constraint(equalTo: connectionStatusView.leadingAnchor, constant: -12),
184+
inboxLabel.centerYAnchor.constraint(equalTo: headerView.centerYAnchor),
236185

237186
// Separator constraints
238187
separatorView.leadingAnchor.constraint(equalTo: headerView.leadingAnchor),
@@ -247,79 +196,10 @@ public class ChatwootViewController: UIViewController {
247196
webView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
248197
])
249198

250-
updateUI()
251199
}
252200

253-
/// Updates the UI based on current state
254-
private func updateUI() {
255-
profileLabel.text = profile.name
256-
// profileLabel.textColor is set in setupUI and doesn't need to change based on loading state here
257-
// It's now based on themeColor.isLight
258-
259-
if isProfileLoading {
260-
loadingIndicator.startAnimating()
261-
avatarImageView.image = nil
262-
} else {
263-
loadingIndicator.stopAnimating()
264-
265-
if let avatarUrl = profile.avatarUrl, let url = URL(string: avatarUrl) {
266-
loadAvatarImage(from: url)
267-
} else {
268-
setInitialsAvatar()
269-
}
270-
}
271-
}
272201

273-
/// Loads avatar image from URL
274-
private func loadAvatarImage(from url: URL) {
275-
URLSession.shared.dataTask(with: url) { [weak self] data, response, error in
276-
DispatchQueue.main.async {
277-
guard let self = self,
278-
let data = data,
279-
let image = UIImage(data: data) else {
280-
self?.setInitialsAvatar()
281-
return
282-
}
283-
self.avatarImageView.image = image
284-
}
285-
}.resume()
286-
}
287202

288-
/// Sets initials avatar
289-
private func setInitialsAvatar() {
290-
let initials = profile.name.initials
291-
let size = CGSize(width: 32, height: 32)
292-
let contentColor: UIColor = ChatwootSDK.getCurrentTextColor()
293-
294-
UIGraphicsBeginImageContextWithOptions(size, false, 0)
295-
let context = UIGraphicsGetCurrentContext()
296-
297-
// Draw background circle
298-
contentColor.withAlphaComponent(0.1).setFill() // Use content color for background
299-
context?.fillEllipse(in: CGRect(origin: .zero, size: size))
300-
301-
// Draw initials text
302-
let font = UIFont.systemFont(ofSize: 14, weight: .medium)
303-
let textAttributes: [NSAttributedString.Key: Any] = [
304-
.font: font,
305-
.foregroundColor: contentColor // Use content color for text
306-
]
307-
308-
let textSize = initials.size(withAttributes: textAttributes)
309-
let textRect = CGRect(
310-
x: (size.width - textSize.width) / 2,
311-
y: (size.height - textSize.height) / 2,
312-
width: textSize.width,
313-
height: textSize.height
314-
)
315-
316-
initials.draw(in: textRect, withAttributes: textAttributes)
317-
318-
let image = UIGraphicsGetImageFromCurrentImageContext()
319-
UIGraphicsEndImageContext()
320-
321-
avatarImageView.image = image
322-
}
323203

324204
/// Loads the WebView content
325205
private func loadWebView() {
@@ -335,29 +215,6 @@ public class ChatwootViewController: UIViewController {
335215
webView.loadHTMLString(htmlContent, baseURL: bundleURL)
336216
}
337217

338-
/// Loads profile data from API
339-
private func loadProfileData() {
340-
ProfileAPI.fetchProfile(
341-
baseUrl: configuration.apiHost,
342-
token: configuration.accessToken
343-
) { [weak self] result in
344-
DispatchQueue.main.async {
345-
guard let self = self else { return }
346-
347-
switch result {
348-
case .success(let fetchedProfile):
349-
self.profile = fetchedProfile
350-
self.isProfileLoading = false
351-
case .failure(let error):
352-
print("[Chatwoot] Error loading profile: \(error.localizedDescription)")
353-
self.profile = ChatwootProfile(name: "Chat User")
354-
self.isProfileLoading = false
355-
}
356-
357-
self.updateUI()
358-
}
359-
}
360-
}
361218

362219
/// Sets up network monitoring for connection status
363220
private func setupNetworkMonitoring() {

0 commit comments

Comments
 (0)