diff --git a/android/capacitor/src/main/java/com/getcapacitor/Bridge.java b/android/capacitor/src/main/java/com/getcapacitor/Bridge.java index 3b135910c..defca0fbf 100644 --- a/android/capacitor/src/main/java/com/getcapacitor/Bridge.java +++ b/android/capacitor/src/main/java/com/getcapacitor/Bridge.java @@ -655,6 +655,7 @@ private void registerAllPlugins() { this.registerPlugin(com.getcapacitor.plugin.CapacitorCookies.class); this.registerPlugin(com.getcapacitor.plugin.WebView.class); this.registerPlugin(com.getcapacitor.plugin.CapacitorHttp.class); + this.registerPlugin(com.getcapacitor.plugin.SystemBars.class); for (Class pluginClass : this.initialPlugins) { this.registerPlugin(pluginClass); diff --git a/android/capacitor/src/main/java/com/getcapacitor/plugin/SystemBars.java b/android/capacitor/src/main/java/com/getcapacitor/plugin/SystemBars.java new file mode 100644 index 000000000..74bdfcb28 --- /dev/null +++ b/android/capacitor/src/main/java/com/getcapacitor/plugin/SystemBars.java @@ -0,0 +1,200 @@ +package com.getcapacitor.plugin; + +import android.content.pm.PackageInfo; +import android.content.res.Configuration; +import android.view.View; +import android.view.Window; +import androidx.core.graphics.Insets; +import androidx.core.view.ViewCompat; +import androidx.core.view.WindowCompat; +import androidx.core.view.WindowInsetsCompat; +import androidx.core.view.WindowInsetsControllerCompat; +import androidx.webkit.WebViewCompat; +import com.getcapacitor.Plugin; +import com.getcapacitor.PluginCall; +import com.getcapacitor.PluginMethod; +import com.getcapacitor.annotation.CapacitorPlugin; +import java.util.Locale; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +@CapacitorPlugin +public class SystemBars extends Plugin { + + static final String STYLE_LIGHT = "LIGHT"; + static final String STYLE_DARK = "DARK"; + static final String STYLE_DEFAULT = "DEFAULT"; + static final String INSET_TOP = "top"; + static final String INSET_BOTTOM = "bottom"; + + @Override + public void load() { + super.load(); + initSystemBars(); + } + + private boolean hasFixedWebView() { + PackageInfo packageInfo = WebViewCompat.getCurrentWebViewPackage(bridge.getContext()); + Pattern pattern = Pattern.compile("(\\d+)"); + Matcher matcher = pattern.matcher(packageInfo.versionName); + + if (!matcher.find()) { + return false; + } + + String majorVersionStr = matcher.group(0); + int majorVersion = Integer.parseInt(majorVersionStr); + + return majorVersion >= 140; + } + + private void initSystemBars() { + boolean enableInsets = getConfig().getBoolean("enableInsets", true); + String style = getConfig().getString("style", STYLE_DEFAULT).toUpperCase(); + boolean hidden = getConfig().getBoolean("hidden", false); + + if (enableInsets) { + setupSafeAreaInsets(); + } + + getBridge() + .executeOnMainThread(() -> { + setStyle(style, ""); + setHidden(hidden, ""); + }); + } + + @PluginMethod + public void setStyle(final PluginCall call) { + String inset = call.getString("inset", "").toLowerCase(Locale.US); + String style = call.getString("style", STYLE_DEFAULT); + + getBridge() + .executeOnMainThread(() -> { + setStyle(style, inset); + call.resolve(); + }); + } + + @PluginMethod + public void show(final PluginCall call) { + String inset = call.getString("inset", "").toLowerCase(Locale.US); + + getBridge() + .executeOnMainThread(() -> { + setHidden(false, inset); + call.resolve(); + }); + } + + @PluginMethod + public void hide(final PluginCall call) { + String inset = call.getString("inset", "").toLowerCase(Locale.US); + + getBridge() + .executeOnMainThread(() -> { + setHidden(true, inset); + call.resolve(); + }); + } + + @PluginMethod + public void setAnimation(final PluginCall call) { + call.resolve(); + } + + private void setupSafeAreaInsets() { + View decorView = getActivity().getWindow().getDecorView(); + + ViewCompat.setOnApplyWindowInsetsListener(decorView, (v, insets) -> { + if (!this.hasFixedWebView()) { + Insets safeArea = insets.getInsets(WindowInsetsCompat.Type.systemBars() | WindowInsetsCompat.Type.displayCutout()); + injectSafeAreaCSS(safeArea.top, safeArea.right, safeArea.bottom, safeArea.left); + + return WindowInsetsCompat.CONSUMED; + } + + return insets; + }); + } + + private void injectSafeAreaCSS(int top, int right, int bottom, int left) { + // Convert pixels to density-independent pixels + float density = getActivity().getResources().getDisplayMetrics().density; + float topPx = top / density; + float rightPx = right / density; + float bottomPx = bottom / density; + float leftPx = left / density; + + // Execute JavaScript to inject the CSS + getBridge() + .executeOnMainThread(() -> { + if (bridge != null && bridge.getWebView() != null) { + String script = String.format( + Locale.US, + """ + try { + document.documentElement.style.setProperty("--safe-area-inset-top", "%dpx"); + document.documentElement.style.setProperty("--safe-area-inset-right", "%dpx"); + document.documentElement.style.setProperty("--safe-area-inset-bottom", "%dpx"); + document.documentElement.style.setProperty("--safe-area-inset-left", "%dpx"); + window.dispatchEvent(new CustomEvent('safeAreaChanged')); + } catch(e) { console.error('Error injecting safe area CSS:', e); } + """, + (int) topPx, + (int) rightPx, + (int) bottomPx, + (int) leftPx + ); + + bridge.getWebView().evaluateJavascript(script, null); + } + }); + } + + private void setStyle(String style, String inset) { + if (style.equals(STYLE_DEFAULT)) { + style = getStyleForTheme(); + } + + Window window = getActivity().getWindow(); + WindowInsetsControllerCompat windowInsetsControllerCompat = WindowCompat.getInsetsController(window, window.getDecorView()); + if (inset.isEmpty() || inset.equals(INSET_TOP)) { + windowInsetsControllerCompat.setAppearanceLightStatusBars(!style.equals(STYLE_DARK)); + } + + if (inset.isEmpty() || inset.equals(INSET_BOTTOM)) { + windowInsetsControllerCompat.setAppearanceLightNavigationBars(!style.equals(STYLE_DARK)); + } + } + + private void setHidden(boolean hide, String inset) { + Window window = getActivity().getWindow(); + WindowInsetsControllerCompat windowInsetsControllerCompat = WindowCompat.getInsetsController(window, window.getDecorView()); + + if (hide) { + if (inset.isEmpty() || inset.equals(INSET_TOP)) { + windowInsetsControllerCompat.hide(WindowInsetsCompat.Type.statusBars()); + } + if (inset.isEmpty() || inset.equals(INSET_BOTTOM)) { + windowInsetsControllerCompat.hide(WindowInsetsCompat.Type.navigationBars()); + } + return; + } + + if (inset.isEmpty() || inset.equals(INSET_TOP)) { + windowInsetsControllerCompat.show(WindowInsetsCompat.Type.systemBars()); + } + if (inset.isEmpty() || inset.equals(INSET_BOTTOM)) { + windowInsetsControllerCompat.show(WindowInsetsCompat.Type.navigationBars()); + } + } + + private String getStyleForTheme() { + int currentNightMode = getActivity().getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK; + if (currentNightMode != Configuration.UI_MODE_NIGHT_YES) { + return STYLE_LIGHT; + } + return STYLE_DARK; + } +} diff --git a/cli/src/declarations.ts b/cli/src/declarations.ts index 046516efa..83c1f307a 100644 --- a/cli/src/declarations.ts +++ b/cli/src/declarations.ts @@ -710,4 +710,40 @@ export interface PluginsConfig { */ enabled?: boolean; }; + + /** + * System Bars plugin configuration + * + * @since 8.0.0 + */ + SystemBars?: { + /** + * Enables the injection of device css insets into the webview. + * + * Only available on Android. + * + * @default true + */ + enableInsets?: boolean; + + /** + * Style of the text / icons of the system bars. + */ + style?: string; + + /** + * If the system bars are hidden or not. + */ + hidden?: boolean; + + /** + * The type of status bar animation used when showing or hiding. + * + * This option is only supported on iOS. + * + * @default 'FADE' + * + */ + animation?: 'FADE' | 'NONE'; + }; } diff --git a/core/package.json b/core/package.json index d6bd42842..be17a5e8c 100644 --- a/core/package.json +++ b/core/package.json @@ -27,7 +27,7 @@ "build": "npm run clean && npm run docgen && npm run transpile && npm run rollup", "build:nativebridge": "tsc native-bridge.ts --target es2017 --moduleResolution node --outDir build && rollup --config rollup.bridge.config.js", "clean": "rimraf dist", - "docgen": "docgen --api CapacitorCookiesPlugin --output-readme cookies.md && docgen --api CapacitorHttpPlugin --output-readme http.md", + "docgen": "docgen --api CapacitorCookiesPlugin --output-readme cookies.md && docgen --api CapacitorHttpPlugin --output-readme http.md && docgen --api SystemBarsPlugin --output-readme systembars.md", "prepublishOnly": "npm run build", "rollup": "rollup --config rollup.config.js", "transpile": "tsc", diff --git a/core/src/core-plugins.ts b/core/src/core-plugins.ts index 84cfd5fca..a475e904d 100644 --- a/core/src/core-plugins.ts +++ b/core/src/core-plugins.ts @@ -494,3 +494,158 @@ export const CapacitorHttp = registerPlugin('CapacitorHttp' }); /******** END HTTP PLUGIN ********/ + +/******** SYSTEM BARS PLUGIN ********/ + +/** + * Available status bar styles. + */ +export enum SystemBarStyle { + /** + * Light system bar content on a dark background. + * + * @since 8.0.0 + */ + Dark = 'DARK', + + /** + * For dark system bar content on a light background. + * + * @since 8.0.0 + */ + Light = 'LIGHT', + + /** + * The style is based on the device appearance or the underlying content. + * If the device is using Dark mode, the statusbar text will be light. + * If the device is using Light mode, the statusbar text will be dark. + * + * @since 8.0.0 + */ + Default = 'DEFAULT', +} + +/** + * Available iOS status bar animations. + */ +export type SystemBarAnimation = 'FADE' | 'NONE'; + +/** + * Available inset edges. + */ +export type SystemBarInsets = 'top' | 'bottom' | 'left' | 'right'; + +export interface SystemBarStyleOptions { + /** + * Style of the text and icons of the system bars. + * + * @since 8.0.0 + * @default default + * @example "DARK" + */ + style: SystemBarStyle; + + /** + * The inset edge for which to apply the style. + * + * Only available on Android. + * + * @since 8.0.0 + * @default null + * @example "top" + */ + inset?: Omit; +} + +export interface SystemBarVisibilityOptions { + /** + * The inset edge for which to hide. + * + * Only available on Android. + * + * @since 8.0.0 + * @default null + * @example "top" + */ + inset?: SystemBarInsets; + + /** + * The type of status bar animation used when showing or hiding. + * + * This option is only supported on iOS. + * + * @default 'FADE' + * + * @since 8.0.0 + */ + animation?: SystemBarAnimation; +} + +export interface SystemBarsAnimationOptions { + /** + * The type of status bar animation used when showing or hiding. + * + * This option is only supported on iOS. + * + * @default 'FADE' + * + * @since 8.0.0 + */ + animation: SystemBarAnimation; +} + +export interface SystemBarsPlugin { + /** + * Set the current style of the system bars. + * + * @since 8.0.0 + */ + setStyle(options: SystemBarStyleOptions): Promise; + + /** + * Show the status / system bars. + * + * @since 8.0.0 + */ + show(options: SystemBarVisibilityOptions): Promise; + + /** + * Hide the status / system bars. + * + * @since 8.0.0 + */ + hide(options: SystemBarVisibilityOptions): Promise; + + /** + * Set the animation to use when showing / hiding the status bar. + * + * Only available on iOS. + * + * @since 8.0.0 + */ + setAnimation(options: SystemBarsAnimationOptions): Promise; +} + +export class SystemBarsPluginWeb extends WebPlugin implements SystemBarsPlugin { + async setStyle(): Promise { + this.unavailable('not available for web'); + } + + async setAnimation(): Promise { + this.unavailable('not available for web'); + } + + async show(): Promise { + this.unavailable('not available for web'); + } + + async hide(): Promise { + this.unavailable('not available for web'); + } +} + +export const SystemBars = registerPlugin('SystemBars', { + web: () => new SystemBarsPluginWeb(), +}); + +/******** END SYSTEM BARS PLUGIN ********/ diff --git a/core/src/index.ts b/core/src/index.ts index b4f9db777..cfcae1f5e 100644 --- a/core/src/index.ts +++ b/core/src/index.ts @@ -17,7 +17,16 @@ export { Capacitor, registerPlugin } from './global'; export { WebPlugin, ListenerCallback } from './web-plugin'; // Core Plugins APIs -export { CapacitorCookies, CapacitorHttp, WebView, buildRequestInit } from './core-plugins'; +export { + SystemBars, + SystemBarInsets, + SystemBarStyle, + SystemBarAnimation, + CapacitorCookies, + CapacitorHttp, + WebView, + buildRequestInit, +} from './core-plugins'; // Core Plugin definitions export type { @@ -31,6 +40,8 @@ export type { HttpResponseType, WebViewPath, WebViewPlugin, + SystemBarVisibilityOptions, + SystemBarStyleOptions, } from './core-plugins'; // Constants diff --git a/core/systembars.md b/core/systembars.md new file mode 100644 index 000000000..ce320506f --- /dev/null +++ b/core/systembars.md @@ -0,0 +1,165 @@ +# SystemBars + +## API + + + +* [`setStyle(...)`](#setstyle) +* [`show(...)`](#show) +* [`hide(...)`](#hide) +* [`setAnimation(...)`](#setanimation) +* [Interfaces](#interfaces) +* [Type Aliases](#type-aliases) +* [Enums](#enums) + + + + + + +### setStyle(...) + +```typescript +setStyle(options: SystemBarStyleOptions) => Promise +``` + +Set the current style of the system bars. + +| Param | Type | +| ------------- | ----------------------------------------------------------------------- | +| **`options`** | SystemBarStyleOptions | + +**Since:** 8.0.0 + +-------------------- + + +### show(...) + +```typescript +show(options: SystemBarVisibilityOptions) => Promise +``` + +Show the status / system bars. + +| Param | Type | +| ------------- | --------------------------------------------------------------------------------- | +| **`options`** | SystemBarVisibilityOptions | + +**Since:** 8.0.0 + +-------------------- + + +### hide(...) + +```typescript +hide(options: SystemBarVisibilityOptions) => Promise +``` + +Hide the status / system bars. + +| Param | Type | +| ------------- | --------------------------------------------------------------------------------- | +| **`options`** | SystemBarVisibilityOptions | + +**Since:** 8.0.0 + +-------------------- + + +### setAnimation(...) + +```typescript +setAnimation(options: SystemBarsAnimationOptions) => Promise +``` + +Set the animation to use when showing / hiding the status bar. + +Only available on iOS. + +| Param | Type | +| ------------- | --------------------------------------------------------------------------------- | +| **`options`** | SystemBarsAnimationOptions | + +**Since:** 8.0.0 + +-------------------- + + +### Interfaces + + +#### SystemBarStyleOptions + +| Prop | Type | Description | Default | Since | +| ----------- | ---------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------- | -------------------- | ----- | +| **`style`** | SystemBarStyle | Style of the text and icons of the system bars. | default | 8.0.0 | +| **`inset`** | Omit<SystemBarInsets, 'left, right'> | The inset edge for which to apply the style. Only available on Android. | null | 8.0.0 | + + +#### SystemBarVisibilityOptions + +| Prop | Type | Description | Default | Since | +| --------------- | ----------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- | ------------------- | ----- | +| **`inset`** | SystemBarInsets | The inset edge for which to hide. Only available on Android. | null | 8.0.0 | +| **`animation`** | SystemBarAnimation | The type of status bar animation used when showing or hiding. This option is only supported on iOS. | 'FADE' | 8.0.0 | + + +#### SystemBarsAnimationOptions + +| Prop | Type | Description | Default | Since | +| --------------- | ----------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- | ------------------- | ----- | +| **`animation`** | SystemBarAnimation | The type of status bar animation used when showing or hiding. This option is only supported on iOS. | 'FADE' | 8.0.0 | + + +### Type Aliases + + +#### Omit + +Construct a type with the properties of T except for those in type K. + +Pick<T, Exclude<keyof T, K>> + + +#### Pick + +From T, pick a set of properties whose keys are in the union K + +{ [P in K]: T[P]; } + + +#### Exclude + +Exclude from T those types that are assignable to U + +T extends U ? never : T + + +#### SystemBarInsets + +Available inset edges. + +'top' | 'bottom' | 'left' | 'right' + + +#### SystemBarAnimation + +Available iOS status bar animations. + +'FADE' | 'NONE' + + +### Enums + + +#### SystemBarStyle + +| Members | Value | Description | Since | +| ------------- | ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----- | +| **`Dark`** | 'DARK' | Light system bar content on a dark background. | 8.0.0 | +| **`Light`** | 'LIGHT' | For dark system bar content on a light background. | 8.0.0 | +| **`Default`** | 'DEFAULT' | The style is based on the device appearance or the underlying content. If the device is using Dark mode, the statusbar text will be light. If the device is using Light mode, the statusbar text will be dark. | 8.0.0 | + + diff --git a/ios/Capacitor/Capacitor.xcodeproj/project.pbxproj b/ios/Capacitor/Capacitor.xcodeproj/project.pbxproj index 843ee1e10..b060d9f7d 100644 --- a/ios/Capacitor/Capacitor.xcodeproj/project.pbxproj +++ b/ios/Capacitor/Capacitor.xcodeproj/project.pbxproj @@ -80,6 +80,7 @@ 62FABD1A25AE5C01007B3814 /* Array+Capacitor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62FABD1925AE5C01007B3814 /* Array+Capacitor.swift */; }; 62FABD2325AE60BA007B3814 /* BridgedTypesTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 62FABD2225AE60BA007B3814 /* BridgedTypesTests.m */; }; 62FABD2B25AE6182007B3814 /* BridgedTypesHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62FABD2A25AE6182007B3814 /* BridgedTypesHelper.swift */; }; + 957BD9402E78A4A50056874C /* SystemBars.swift in Sources */ = {isa = PBXBuildFile; fileRef = 957BD93E2E78A4A20056874C /* SystemBars.swift */; }; A327E6B628DB8B2900CA8B0A /* HttpRequestHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = A327E6B228DB8B2800CA8B0A /* HttpRequestHandler.swift */; }; A327E6B728DB8B2900CA8B0A /* CapacitorHttp.swift in Sources */ = {isa = PBXBuildFile; fileRef = A327E6B428DB8B2900CA8B0A /* CapacitorHttp.swift */; }; A327E6B828DB8B2900CA8B0A /* CapacitorUrlRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = A327E6B528DB8B2900CA8B0A /* CapacitorUrlRequest.swift */; }; @@ -237,6 +238,7 @@ 62FABD1925AE5C01007B3814 /* Array+Capacitor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Array+Capacitor.swift"; sourceTree = ""; }; 62FABD2225AE60BA007B3814 /* BridgedTypesTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BridgedTypesTests.m; sourceTree = ""; }; 62FABD2A25AE6182007B3814 /* BridgedTypesHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BridgedTypesHelper.swift; sourceTree = ""; }; + 957BD93E2E78A4A20056874C /* SystemBars.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SystemBars.swift; sourceTree = ""; }; A327E6B228DB8B2800CA8B0A /* HttpRequestHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HttpRequestHandler.swift; sourceTree = ""; }; A327E6B428DB8B2900CA8B0A /* CapacitorHttp.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CapacitorHttp.swift; sourceTree = ""; }; A327E6B528DB8B2900CA8B0A /* CapacitorUrlRequest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CapacitorUrlRequest.swift; sourceTree = ""; }; @@ -420,6 +422,7 @@ 62959AEA2524DA7700A3D7F1 /* Plugins */ = { isa = PBXGroup; children = ( + 957BD93E2E78A4A20056874C /* SystemBars.swift */, A327E6B428DB8B2900CA8B0A /* CapacitorHttp.swift */, A327E6B528DB8B2900CA8B0A /* CapacitorUrlRequest.swift */, A327E6B228DB8B2800CA8B0A /* HttpRequestHandler.swift */, @@ -735,6 +738,7 @@ 62959B302524DA7800A3D7F1 /* UIStatusBarManager+CAPHandleTapAction.m in Sources */, 62959B392524DA7800A3D7F1 /* CapacitorExtension.swift in Sources */, A327E6B628DB8B2900CA8B0A /* HttpRequestHandler.swift in Sources */, + 957BD9402E78A4A50056874C /* SystemBars.swift in Sources */, 62959B422524DA7800A3D7F1 /* DocLinks.swift in Sources */, 62FABD1A25AE5C01007B3814 /* Array+Capacitor.swift in Sources */, A7BE62CC2B486A5400165ACB /* KeyValueStore.swift in Sources */, diff --git a/ios/Capacitor/Capacitor/CapacitorBridge.swift b/ios/Capacitor/Capacitor/CapacitorBridge.swift index 9caa21850..8b0026ad9 100644 --- a/ios/Capacitor/Capacitor/CapacitorBridge.swift +++ b/ios/Capacitor/Capacitor/CapacitorBridge.swift @@ -302,7 +302,7 @@ open class CapacitorBridge: NSObject, CAPBridgeProtocol { Register all plugins that have been declared */ func registerPlugins() { - var pluginList: [AnyClass] = [CAPHttpPlugin.self, CAPConsolePlugin.self, CAPWebViewPlugin.self, CAPCookiesPlugin.self] + var pluginList: [AnyClass] = [CAPHttpPlugin.self, CAPConsolePlugin.self, CAPWebViewPlugin.self, CAPCookiesPlugin.self, CAPSystemBarsPlugin.self] if autoRegisterPlugins { do { diff --git a/ios/Capacitor/Capacitor/Plugins/SystemBars.swift b/ios/Capacitor/Capacitor/Plugins/SystemBars.swift new file mode 100644 index 000000000..80e9e4f09 --- /dev/null +++ b/ios/Capacitor/Capacitor/Plugins/SystemBars.swift @@ -0,0 +1,91 @@ +import Foundation + +@objc(CAPSystemBarsPlugin) +public class CAPSystemBarsPlugin: CAPPlugin, CAPBridgedPlugin { + public let identifier = "CAPSystemBarsPlugin" + public let jsName = "SystemBars" + public let pluginMethods: [CAPPluginMethod] = [ + CAPPluginMethod(name: "setStyle", returnType: CAPPluginReturnNone), + CAPPluginMethod(name: "setAnimation", returnType: CAPPluginReturnNone), + CAPPluginMethod(name: "show", returnType: CAPPluginReturnNone), + CAPPluginMethod(name: "hide", returnType: CAPPluginReturnNone) + ] + + enum Style: String { + case dark = "DARK" + case light = "LIGHT" + case defaultStyle = "DEFAULT" + } + + @objc override public func load() { + let style = getConfig().getString("style", Style.defaultStyle.rawValue) ?? Style.defaultStyle.rawValue + let hidden = getConfig().getBoolean("hidden", false) + let animation = getConfig().getString("animation", "FADE") ?? "FADE" + + setStyle(style: style) + setHidden(hidden: hidden) + setAnimation(animation: animation) + } + + @objc func setStyle(_ call: CAPPluginCall) { + setStyle(style: call.getString("style") ?? Style.defaultStyle.rawValue) + + call.resolve() + } + + @objc func show(_ call: CAPPluginCall) { + if let animation = call.getString("animation") { + setAnimation(animation: animation) + } + + setHidden(hidden: false) + + call.resolve() + } + + @objc func hide(_ call: CAPPluginCall) { + if let animation = call.getString("animation") { + setAnimation(animation: animation) + } + + setHidden(hidden: true) + + call.resolve() + } + + @objc func setAnimation(_ call: CAPPluginCall) { + let animation = call.getString("animation", "FADE") + setAnimation(animation: animation) + + call.resolve() + } + + func setStyle(style: String) { + var newStyle: UIStatusBarStyle = .default + + if let style = Style(rawValue: style) { + switch style { + case .dark: + newStyle = .lightContent + case .light: + newStyle = .darkContent + case .defaultStyle: + newStyle = .default + } + } + + bridge?.statusBarStyle = newStyle + } + + func setHidden(hidden: Bool) { + bridge?.statusBarVisible = !hidden + } + + func setAnimation(animation: String) { + if animation == "NONE" { + bridge?.statusBarAnimation = .none + } else { + bridge?.statusBarAnimation = .fade + } + } +}