diff --git a/status-bar/README.md b/status-bar/README.md index cd7ef29c8..63f8b5822 100644 --- a/status-bar/README.md +++ b/status-bar/README.md @@ -20,9 +20,6 @@ The status bar visibility defaults to visible and the style defaults to `Style.Default`. You can change these defaults by adding `UIStatusBarHidden` and/or `UIStatusBarStyle` in `Info.plist`. -`setBackgroundColor` and `setOverlaysWebView` are currently not supported on -iOS devices. - ## Example ```typescript @@ -33,7 +30,7 @@ window.addEventListener('statusTap', function () { console.log('statusbar tapped'); }); -// Display content under transparent status bar (Android only) +// Display content under transparent status bar StatusBar.setOverlaysWebView({ overlay: true }); const setStatusBarStyleDark = async () => { @@ -53,6 +50,57 @@ const showStatusBar = async () => { }; ``` +## Configuration + + + + +These config values are available: + +| Prop | Type | Description | Default | Since | +| --------------------- | -------------------- | ----------------------------------------------------------------------------------------------------------- | -------------------- | ----- | +| **`overlaysWebView`** | boolean | Whether the statusbar is overlaid or not. | true | 1.0.0 | +| **`style`** | string | Style of the text of the status bar. | default | 1.0.0 | +| **`backgroundColor`** | string | Color of the background of the statusbar in hex format, #RRGGBB. Doesn't work if `overlaysWebView` is true. | #000000 | 1.0.0 | + +### Examples + +In `capacitor.config.json`: + +```json +{ + "plugins": { + "StatusBar": { + "overlaysWebView": false, + "style": "DARK", + "backgroundColor": "#ffffffff" + } + } +} +``` + +In `capacitor.config.ts`: + +```ts +/// + +import { CapacitorConfig } from '@capacitor/cli'; + +const config: CapacitorConfig = { + plugins: { + StatusBar: { + overlaysWebView: false, + style: "DARK", + backgroundColor: "#ffffffff", + }, + }, +}; + +export default config; +``` + + + ## API @@ -96,8 +144,6 @@ setBackgroundColor(options: BackgroundColorOptions) => Promise Set the background color of the status bar. -This method is only supported on Android. - | Param | Type | | ------------- | ------------------------------------------------------------------------- | | **`options`** | BackgroundColorOptions | @@ -169,8 +215,6 @@ setOverlaysWebView(options: SetOverlaysWebViewOptions) => Promise Set whether or not the status bar should overlay the webview to allow usage of the space underneath it. -This method is only supported on Android. - | Param | Type | | ------------- | ------------------------------------------------------------------------------- | | **`options`** | SetOverlaysWebViewOptions | @@ -192,9 +236,9 @@ This method is only supported on Android. #### BackgroundColorOptions -| Prop | Type | Description | Since | -| ----------- | ------------------- | ------------------------------------------------------------------------------------------- | ----- | -| **`color`** | string | A hex color to which the status bar color is set. This option is only supported on Android. | 1.0.0 | +| Prop | Type | Description | Since | +| ----------- | ------------------- | ------------------------------------------------- | ----- | +| **`color`** | string | A hex color to which the status bar color is set. | 1.0.0 | #### AnimationOptions @@ -206,12 +250,12 @@ This method is only supported on Android. #### StatusBarInfo -| Prop | Type | Description | Since | -| -------------- | --------------------------------------- | ----------------------------------------------------------------------------------- | ----- | -| **`visible`** | boolean | Whether the status bar is visible or not. | 1.0.0 | -| **`style`** | Style | The current status bar style. | 1.0.0 | -| **`color`** | string | The current status bar color. This option is only supported on Android. | 1.0.0 | -| **`overlays`** | boolean | Whether the statusbar is overlaid or not. This option is only supported on Android. | 1.0.0 | +| Prop | Type | Description | Since | +| -------------- | --------------------------------------- | ----------------------------------------- | ----- | +| **`visible`** | boolean | Whether the status bar is visible or not. | 1.0.0 | +| **`style`** | Style | The current status bar style. | 1.0.0 | +| **`color`** | string | The current status bar color. | 1.0.0 | +| **`overlays`** | boolean | Whether the statusbar is overlaid or not. | 1.0.0 | #### SetOverlaysWebViewOptions diff --git a/status-bar/android/src/main/java/com/capacitorjs/plugins/statusbar/StatusBar.java b/status-bar/android/src/main/java/com/capacitorjs/plugins/statusbar/StatusBar.java index 01d354a29..1a903d133 100644 --- a/status-bar/android/src/main/java/com/capacitorjs/plugins/statusbar/StatusBar.java +++ b/status-bar/android/src/main/java/com/capacitorjs/plugins/statusbar/StatusBar.java @@ -1,6 +1,7 @@ package com.capacitorjs.plugins.statusbar; import android.graphics.Color; +import android.util.DisplayMetrics; import android.view.View; import android.view.Window; import android.view.WindowManager; @@ -16,11 +17,15 @@ public class StatusBar { private final AppCompatActivity activity; private final String defaultStyle; - public StatusBar(AppCompatActivity activity) { + public StatusBar(AppCompatActivity activity, StatusBarConfig config) { // save initial color of the status bar this.activity = activity; this.currentStatusBarColor = activity.getWindow().getStatusBarColor(); this.defaultStyle = getStyle(); + + setBackgroundColor(config.getBackgroundColor()); + setStyle(config.getStyle()); + setOverlaysWebView(config.isOverlaysWebView()); } public void setStyle(String style) { @@ -93,6 +98,7 @@ public StatusBarInfo getInfo() { info.setOverlays(getIsOverlaid()); info.setVisible(isVisible); info.setColor(String.format("#%06X", (0xFFFFFF & window.getStatusBarColor()))); + info.setHeight(getStatusBarHeight()); return info; } @@ -105,4 +111,17 @@ private String getStyle() { } return style; } + + private int getStatusBarHeight() { + int statusbarHeight = 0; + int resourceId = activity.getApplicationContext().getResources().getIdentifier("status_bar_height", "dimen", "android"); + if (resourceId > 0) { + statusbarHeight = (int) activity.getApplicationContext().getResources().getDimension(resourceId); + } + + DisplayMetrics metrics = activity.getApplicationContext().getResources().getDisplayMetrics(); + float densityDpi = metrics.density; + + return (int) (statusbarHeight / densityDpi); + } } diff --git a/status-bar/android/src/main/java/com/capacitorjs/plugins/statusbar/StatusBarConfig.java b/status-bar/android/src/main/java/com/capacitorjs/plugins/statusbar/StatusBarConfig.java new file mode 100644 index 000000000..6deed46db --- /dev/null +++ b/status-bar/android/src/main/java/com/capacitorjs/plugins/statusbar/StatusBarConfig.java @@ -0,0 +1,34 @@ +package com.capacitorjs.plugins.statusbar; + +import com.getcapacitor.util.WebColor; + +public class StatusBarConfig { + + private boolean overlaysWebView = true; + private Integer backgroundColor = WebColor.parseColor("#000000"); + private String style = "DEFAULT"; + + public boolean isOverlaysWebView() { + return overlaysWebView; + } + + public void setOverlaysWebView(boolean overlaysWebView) { + this.overlaysWebView = overlaysWebView; + } + + public Integer getBackgroundColor() { + return backgroundColor; + } + + public void setBackgroundColor(Integer backgroundColor) { + this.backgroundColor = backgroundColor; + } + + public String getStyle() { + return style; + } + + public void setStyle(String style) { + this.style = style; + } +} diff --git a/status-bar/android/src/main/java/com/capacitorjs/plugins/statusbar/StatusBarInfo.java b/status-bar/android/src/main/java/com/capacitorjs/plugins/statusbar/StatusBarInfo.java index 0b4fd9467..1ca75cb16 100644 --- a/status-bar/android/src/main/java/com/capacitorjs/plugins/statusbar/StatusBarInfo.java +++ b/status-bar/android/src/main/java/com/capacitorjs/plugins/statusbar/StatusBarInfo.java @@ -1,11 +1,14 @@ package com.capacitorjs.plugins.statusbar; -public class StatusBarInfo { +import java.io.Serializable; + +public class StatusBarInfo implements Serializable { private boolean overlays; private boolean visible; private String style; private String color; + private int height; public boolean isOverlays() { return overlays; @@ -38,4 +41,12 @@ public String getColor() { public void setColor(String color) { this.color = color; } + + public int getHeight() { + return height; + } + + public void setHeight(int height) { + this.height = height; + } } diff --git a/status-bar/android/src/main/java/com/capacitorjs/plugins/statusbar/StatusBarPlugin.java b/status-bar/android/src/main/java/com/capacitorjs/plugins/statusbar/StatusBarPlugin.java index a66492014..0f5c5fbda 100644 --- a/status-bar/android/src/main/java/com/capacitorjs/plugins/statusbar/StatusBarPlugin.java +++ b/status-bar/android/src/main/java/com/capacitorjs/plugins/statusbar/StatusBarPlugin.java @@ -1,6 +1,7 @@ package com.capacitorjs.plugins.statusbar; import com.getcapacitor.JSObject; +import com.getcapacitor.Logger; import com.getcapacitor.Plugin; import com.getcapacitor.PluginCall; import com.getcapacitor.PluginMethod; @@ -11,11 +12,44 @@ @CapacitorPlugin(name = "StatusBar") public class StatusBarPlugin extends Plugin { + public static final String statusBarVisibilityChanged = "statusBarVisibilityChanged"; + public static final String statusBarOverlayChanged = "statusBarOverlayChanged"; + private StatusBar implementation; @Override public void load() { - implementation = new StatusBar(getActivity()); + StatusBarConfig config = getStatusBarConfig(); + implementation = new StatusBar(getActivity(), config); + } + + private StatusBarConfig getStatusBarConfig() { + StatusBarConfig config = new StatusBarConfig(); + String backgroundColor = getConfig().getString("backgroundColor"); + if (backgroundColor != null) { + try { + config.setBackgroundColor(WebColor.parseColor(backgroundColor)); + } catch (IllegalArgumentException ex) { + Logger.debug("Background color not applied"); + } + } + config.setStyle(styleFromConfig(getConfig().getString("style", config.getStyle()))); + config.setOverlaysWebView(getConfig().getBoolean("overlaysWebView", config.isOverlaysWebView())); + return config; + } + + private String styleFromConfig(String style) { + switch (style.toLowerCase()) { + case "lightcontent": + case "dark": + return "DARK"; + case "darkcontent": + case "light": + return "LIGHT"; + case "default": + default: + return "DEFAULT"; + } } @PluginMethod @@ -64,6 +98,8 @@ public void hide(final PluginCall call) { .executeOnMainThread( () -> { implementation.hide(); + StatusBarInfo info = implementation.getInfo(); + notifyListeners(statusBarVisibilityChanged, toJSObject(info)); call.resolve(); } ); @@ -76,6 +112,8 @@ public void show(final PluginCall call) { .executeOnMainThread( () -> { implementation.show(); + StatusBarInfo info = implementation.getInfo(); + notifyListeners(statusBarVisibilityChanged, toJSObject(info)); call.resolve(); } ); @@ -84,13 +122,7 @@ public void show(final PluginCall call) { @PluginMethod public void getInfo(final PluginCall call) { StatusBarInfo info = implementation.getInfo(); - - JSObject data = new JSObject(); - data.put("visible", info.isVisible()); - data.put("style", info.getStyle()); - data.put("color", info.getColor()); - data.put("overlays", info.isOverlays()); - call.resolve(data); + call.resolve(toJSObject(info)); } @PluginMethod @@ -100,8 +132,20 @@ public void setOverlaysWebView(final PluginCall call) { .executeOnMainThread( () -> { implementation.setOverlaysWebView(overlays); + StatusBarInfo info = implementation.getInfo(); + notifyListeners(statusBarOverlayChanged, toJSObject(info)); call.resolve(); } ); } + + private JSObject toJSObject(StatusBarInfo info) { + JSObject data = new JSObject(); + data.put("visible", info.isVisible()); + data.put("style", info.getStyle()); + data.put("color", info.getColor()); + data.put("overlays", info.isOverlays()); + data.put("height", info.getHeight()); + return data; + } } diff --git a/status-bar/ios/Sources/StatusBarPlugin/CAPBridgeViewController.swift b/status-bar/ios/Sources/StatusBarPlugin/CAPBridgeViewController.swift new file mode 100644 index 000000000..0786977bf --- /dev/null +++ b/status-bar/ios/Sources/StatusBarPlugin/CAPBridgeViewController.swift @@ -0,0 +1,14 @@ +import Capacitor + +extension CAPBridgeViewController { + + open override func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) + NotificationCenter.default.post(Notification(name: .capacitorViewDidAppear)) + } + + open override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { + super.viewWillTransition(to: size, with: coordinator) + NotificationCenter.default.post(Notification(name: .capacitorViewWillTransition)) + } +} diff --git a/status-bar/ios/Sources/StatusBarPlugin/CAPNotifications.swift b/status-bar/ios/Sources/StatusBarPlugin/CAPNotifications.swift new file mode 100644 index 000000000..64a937fe9 --- /dev/null +++ b/status-bar/ios/Sources/StatusBarPlugin/CAPNotifications.swift @@ -0,0 +1,6 @@ +import Capacitor + +extension Notification.Name { + public static let capacitorViewDidAppear = Notification.Name(rawValue: "CapacitorViewDidAppear") + public static let capacitorViewWillTransition = Notification.Name(rawValue: "CapacitorViewWillTransition") +} diff --git a/status-bar/ios/Sources/StatusBarPlugin/StatusBar.swift b/status-bar/ios/Sources/StatusBarPlugin/StatusBar.swift new file mode 100644 index 000000000..5d4d0bc0d --- /dev/null +++ b/status-bar/ios/Sources/StatusBarPlugin/StatusBar.swift @@ -0,0 +1,166 @@ +import Foundation +import Capacitor + +public class StatusBar { + + private var bridge: CAPBridgeProtocol + private var isOverlayingWebview = true + private var backgroundColor = UIColor.black + private var backgroundView: UIView? + private var observers: [NSObjectProtocol] = [] + + init(bridge: CAPBridgeProtocol, config: StatusBarConfig) { + self.bridge = bridge + setupObservers(with: config) + } + + deinit { + observers.forEach { NotificationCenter.default.removeObserver($0) } + } + + private func setupObservers(with config: StatusBarConfig) { + observers.append(NotificationCenter.default.addObserver(forName: .capacitorViewDidAppear, object: .none, queue: .none) { [weak self] _ in + self?.handleViewDidAppear(config: config) + }) + observers.append(NotificationCenter.default.addObserver(forName: .capacitorStatusBarTapped, object: .none, queue: .none) { [weak self] _ in + self?.bridge.triggerJSEvent(eventName: "statusTap", target: "window") + }) + observers.append(NotificationCenter.default.addObserver(forName: .capacitorViewWillTransition, object: .none, queue: .none) { [weak self] _ in + self?.handleViewWillTransition() + }) + } + + private func handleViewDidAppear(config: StatusBarConfig) { + setStyle(config.style) + setBackgroundColor(config.backgroundColor) + setOverlaysWebView(config.overlaysWebView) + } + + private func handleViewWillTransition() { + DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { [weak self] in + self?.resizeStatusBarBackgroundView() + self?.resizeWebView() + } + } + + func setStyle(_ style: UIStatusBarStyle) { + bridge.statusBarStyle = style + } + + func setBackgroundColor(_ color : UIColor) { + backgroundColor = color + backgroundView?.backgroundColor = color + } + + func setAnimation(_ animation: String) { + if animation == "SLIDE" { + bridge.statusBarAnimation = .slide + } else if animation == "NONE" { + bridge.statusBarAnimation = .none + } else { + bridge.statusBarAnimation = .fade + } + } + + func hide(animation: String) { + setAnimation(animation) + if bridge.statusBarVisible { + bridge.statusBarVisible = false + DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { [weak self] in + self?.resizeWebView() + self?.backgroundView?.removeFromSuperview() + self?.backgroundView?.isHidden = true + } + } + } + + func show(animation: String) { + setAnimation(animation) + if !bridge.statusBarVisible { + bridge.statusBarVisible = true + DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { [self] in + resizeWebView() + if !isOverlayingWebview { + resizeStatusBarBackgroundView() + bridge.webView?.superview?.addSubview(backgroundView!) + } + backgroundView?.isHidden = false + } + } + } + + func getInfo() -> StatusBarInfo { + let style: String + switch bridge.statusBarStyle { + case .default: + style = "DEFAULT" + case .lightContent: + style = "DARK" + case .darkContent: + style = "LIGHT" + @unknown default: + style = "DEFAULT" + } + + return StatusBarInfo( + overlays: isOverlayingWebview, + visible: bridge.statusBarVisible, + style: style, + color: UIColor.capacitor.hex(fromColor: backgroundColor), + height: getStatusBarFrame().size.height + ) + } + + func setOverlaysWebView(_ overlay: Bool) { + if overlay == isOverlayingWebview { return } + isOverlayingWebview = overlay + if overlay { + backgroundView?.removeFromSuperview() + } else { + initializeBackgroundViewIfNeeded() + bridge.webView?.superview?.addSubview(backgroundView!) + } + resizeWebView() + } + + private func resizeWebView() { + guard + let webView = bridge.webView, + let bounds = bridge.viewController?.view.window?.windowScene?.screen.bounds + else { return } + bridge.viewController?.view.frame = bounds + webView.frame = bounds + let statusBarHeight = getStatusBarFrame().size.height; + var webViewFrame = webView.frame; + + if isOverlayingWebview { + let safeAreaTop = webView.safeAreaInsets.top; + if (statusBarHeight >= safeAreaTop && safeAreaTop > 0) { + webViewFrame.origin.y = safeAreaTop == 40 ? 20 : statusBarHeight - safeAreaTop + } else { + webViewFrame.origin.y = 0 + } + } else { + webViewFrame.origin.y = statusBarHeight; + } + webViewFrame.size.height -= webViewFrame.origin.y + webView.frame = webViewFrame + } + + private func resizeStatusBarBackgroundView() { + backgroundView?.frame = getStatusBarFrame() + } + + private func getStatusBarFrame() -> CGRect { + return UIApplication.shared.windows.first(where: { $0.isKeyWindow })?.windowScene?.statusBarManager?.statusBarFrame ?? .zero + } + + private func initializeBackgroundViewIfNeeded() { + if backgroundView == nil { + backgroundView = UIView(frame: getStatusBarFrame()) + backgroundView!.backgroundColor = backgroundColor + backgroundView!.autoresizingMask = [.flexibleWidth, .flexibleBottomMargin] + backgroundView!.isHidden = !bridge.statusBarVisible + } + } +} diff --git a/status-bar/ios/Sources/StatusBarPlugin/StatusBarConfig.swift b/status-bar/ios/Sources/StatusBarPlugin/StatusBarConfig.swift new file mode 100644 index 000000000..7e0bc4c53 --- /dev/null +++ b/status-bar/ios/Sources/StatusBarPlugin/StatusBarConfig.swift @@ -0,0 +1,7 @@ +import UIKit + +public struct StatusBarConfig { + var overlaysWebView = true + var backgroundColor: UIColor = .black + var style: UIStatusBarStyle = .default +} diff --git a/status-bar/ios/Sources/StatusBarPlugin/StatusBarInfo.swift b/status-bar/ios/Sources/StatusBarPlugin/StatusBarInfo.swift new file mode 100644 index 000000000..7e1b8b1a7 --- /dev/null +++ b/status-bar/ios/Sources/StatusBarPlugin/StatusBarInfo.swift @@ -0,0 +1,9 @@ +import Foundation + +public struct StatusBarInfo { + public var overlays: Bool? + public var visible: Bool? + public var style: String? + public var color: String? + public var height: CGFloat? +} diff --git a/status-bar/ios/Sources/StatusBarPlugin/StatusBarPlugin.swift b/status-bar/ios/Sources/StatusBarPlugin/StatusBarPlugin.swift index 6634d064c..d43154007 100644 --- a/status-bar/ios/Sources/StatusBarPlugin/StatusBarPlugin.swift +++ b/status-bar/ios/Sources/StatusBarPlugin/StatusBarPlugin.swift @@ -15,92 +15,121 @@ public class StatusBarPlugin: CAPPlugin, CAPBridgedPlugin { CAPPluginMethod(name: "show", returnType: CAPPluginReturnPromise), CAPPluginMethod(name: "hide", returnType: CAPPluginReturnPromise), CAPPluginMethod(name: "getInfo", returnType: CAPPluginReturnPromise), - CAPPluginMethod(name: "setOverlaysWebView", returnType: CAPPluginReturnPromise) + CAPPluginMethod(name: "setOverlaysWebView", returnType: CAPPluginReturnPromise), ] - private var observer: NSObjectProtocol? - + private var statusBar: StatusBar? + private let statusBarVisibilityChanged = "statusBarVisibilityChanged" + private let statusBarOverlayChanged = "statusBarOverlayChanged" + override public func load() { - observer = NotificationCenter.default.addObserver(forName: Notification.Name.capacitorStatusBarTapped, object: .none, queue: .none) { [weak self] _ in - self?.bridge?.triggerJSEvent(eventName: "statusTap", target: "window") + guard let bridge = bridge else { return } + statusBar = StatusBar(bridge: bridge, config: statusBarConfig()) + } + + private func statusBarConfig() -> StatusBarConfig { + var config = StatusBarConfig() + config.overlaysWebView = getConfig().getBoolean("overlaysWebView", config.overlaysWebView) + if let colorConfig = getConfig().getString("backgroundColor"), let color = UIColor.capacitor.color(fromHex: colorConfig) + { + config.backgroundColor = color + } + if let configStyle = getConfig().getString("style") { + config.style = style(fromString: configStyle) } + return config } - - deinit { - if let observer = observer { - NotificationCenter.default.removeObserver(observer) + + private func style(fromString: String) -> UIStatusBarStyle { + switch fromString.lowercased() { + case "dark", "lightcontent": + return .lightContent + case "light", "darkcontent": + return .darkContent + case "default": + return .default + default: + return .default } } @objc func setStyle(_ call: CAPPluginCall) { let options = call.options! - - if let style = options["style"] as? String { - if style == "DARK" { - bridge?.statusBarStyle = .lightContent - } else if style == "LIGHT" { - bridge?.statusBarStyle = .darkContent - } else if style == "DEFAULT" { - bridge?.statusBarStyle = .default - } + if let styleString = options["style"] as? String { + statusBar?.setStyle(style(fromString: styleString)) } - call.resolve([:]) } @objc func setBackgroundColor(_ call: CAPPluginCall) { - call.unimplemented() - } - - func setAnimation(_ call: CAPPluginCall) { - let animation = call.getString("animation", "FADE") - if animation == "SLIDE" { - bridge?.statusBarAnimation = .slide - } else if animation == "NONE" { - bridge?.statusBarAnimation = .none - } else { - bridge?.statusBarAnimation = .fade + guard + let hexString = call.options["color"] as? String, + let color = UIColor.capacitor.color(fromHex: hexString) + else { return } + DispatchQueue.main.async { [weak self] in + self?.statusBar?.setBackgroundColor(color) } + call.resolve() } - + @objc func hide(_ call: CAPPluginCall) { - setAnimation(call) - bridge?.statusBarVisible = false + let animation = call.getString("animation", "FADE") + DispatchQueue.main.async { [weak self] in + self?.statusBar?.hide(animation: animation) + guard + let info = self?.statusBar?.getInfo(), + let dict = self?.toDict(info), + let event = self?.statusBarVisibilityChanged + else { return } + self?.notifyListeners(event, data: dict); + } call.resolve() } @objc func show(_ call: CAPPluginCall) { - setAnimation(call) - bridge?.statusBarVisible = true + let animation = call.getString("animation", "FADE") + DispatchQueue.main.async { [weak self] in + self?.statusBar?.show(animation: animation) + guard + let info = self?.statusBar?.getInfo(), + let dict = self?.toDict(info), + let event = self?.statusBarVisibilityChanged + else { return } + self?.notifyListeners(event, data: dict); + } call.resolve() } - + @objc func getInfo(_ call: CAPPluginCall) { DispatchQueue.main.async { [weak self] in - guard let bridge = self?.bridge else { - return - } - let style: String - switch bridge.statusBarStyle { - case .default: - if bridge.userInterfaceStyle == UIUserInterfaceStyle.dark { - style = "DARK" - } else { - style = "LIGHT" - } - case .lightContent: - style = "DARK" - default: - style = "LIGHT" - } - - call.resolve([ - "visible": bridge.statusBarVisible, - "style": style - ]) + guard + let info = self?.statusBar?.getInfo(), + let dict = self?.toDict(info) + else { return } + call.resolve(dict) } } @objc func setOverlaysWebView(_ call: CAPPluginCall) { - call.unimplemented() + guard let overlay = call.options["overlay"] as? Bool else { return } + DispatchQueue.main.async { [weak self] in + self?.statusBar?.setOverlaysWebView(overlay) + guard + let info = self?.statusBar?.getInfo(), + let dict = self?.toDict(info), + let event = self?.statusBarOverlayChanged + else { return } + self?.notifyListeners(event, data: dict); + } + call.resolve() + } + + private func toDict(_ info: StatusBarInfo) -> [String: Any] { + return [ + "visible": info.visible!, + "style": info.style!, + "color": info.color!, + "overlays": info.overlays!, + "height": info.height! + ] } } diff --git a/status-bar/ios/Sources/StatusBarPlugin/UIColor.swift b/status-bar/ios/Sources/StatusBarPlugin/UIColor.swift new file mode 100644 index 000000000..584afcc4f --- /dev/null +++ b/status-bar/ios/Sources/StatusBarPlugin/UIColor.swift @@ -0,0 +1,40 @@ +import Capacitor + +public extension CapacitorExtensionTypeWrapper where T: UIColor { + + static func hex(fromColor: UIColor) -> String? { + var red: CGFloat = 0 + var green: CGFloat = 0 + var blue: CGFloat = 0 + var alpha: CGFloat = 0 + + guard fromColor.getRed(&red, green: &green, blue: &blue, alpha: &alpha) else { + assertionFailure("Failed to get RGBA components from UIColor") + return nil + } + + red = max(0, min(1, red)) + green = max(0, min(1, green)) + blue = max(0, min(1, blue)) + alpha = max(0, min(1, alpha)) + + if alpha == 1 { + // RGB + return String( + format: "#%02lX%02lX%02lX", + Int(round(red * 255)), + Int(round(green * 255)), + Int(round(blue * 255)) + ) + } else { + // RGBA + return String( + format: "#%02lX%02lX%02lX%02lX", + Int(round(red * 255)), + Int(round(green * 255)), + Int(round(blue * 255)), + Int(round(alpha * 255)) + ) + } + } +} diff --git a/status-bar/src/definitions.ts b/status-bar/src/definitions.ts index e1f69e384..9e18cb5b5 100644 --- a/status-bar/src/definitions.ts +++ b/status-bar/src/definitions.ts @@ -1,3 +1,42 @@ +/// + +declare module '@capacitor/cli' { + export interface PluginsConfig { + /** + * These config values are available: + */ + StatusBar?: { + /** + * Whether the statusbar is overlaid or not. + * + * @since 1.0.0 + * @default true + * @example false + */ + overlaysWebView?: boolean; + + /** + * Style of the text of the status bar. + * + * @since 1.0.0 + * @default default + * @example "DARK" + */ + style?: string; + + /** + * Color of the background of the statusbar in hex format, #RRGGBB. + * Doesn't work if `overlaysWebView` is true. + * + * @since 1.0.0 + * @default #000000 + * @example "#ffffffff" + */ + backgroundColor?: string; + }; + } +} + export interface StyleOptions { /** * Style of the text of the status bar. @@ -76,8 +115,6 @@ export interface BackgroundColorOptions { /** * A hex color to which the status bar color is set. * - * This option is only supported on Android. - * * @since 1.0.0 */ color: string; @@ -101,8 +138,6 @@ export interface StatusBarInfo { /** * The current status bar color. * - * This option is only supported on Android. - * * @since 1.0.0 */ color?: string; @@ -110,8 +145,6 @@ export interface StatusBarInfo { /** * Whether the statusbar is overlaid or not. * - * This option is only supported on Android. - * * @since 1.0.0 */ overlays?: boolean; @@ -137,8 +170,6 @@ export interface StatusBarPlugin { /** * Set the background color of the status bar. * - * This method is only supported on Android. - * * @since 1.0.0 */ setBackgroundColor(options: BackgroundColorOptions): Promise; @@ -172,8 +203,6 @@ export interface StatusBarPlugin { * Set whether or not the status bar should overlay the webview to allow usage * of the space underneath it. * - * This method is only supported on Android. - * * @since 1.0.0 */ setOverlaysWebView(options: SetOverlaysWebViewOptions): Promise;