Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(iOS): Paint safe areas on iOS mobile #928

Merged
merged 12 commits into from
Dec 13, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions android/app/capacitor.build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ dependencies {
implementation project(':capacitor-keyboard')
implementation project(':capacitor-screen-orientation')
implementation project(':capacitor-splash-screen')
implementation project(':capacitor-status-bar')

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need this empty line?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed

}


Expand Down
3 changes: 3 additions & 0 deletions android/capacitor.settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,6 @@ project(':capacitor-screen-orientation').projectDir = new File('../node_modules/

include ':capacitor-splash-screen'
project(':capacitor-splash-screen').projectDir = new File('../node_modules/@capacitor/splash-screen/android')

include ':capacitor-status-bar'
project(':capacitor-status-bar').projectDir = new File('../node_modules/@capacitor/status-bar/android')
78 changes: 78 additions & 0 deletions ios/App/App/PluginSafeAreasColor.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import Capacitor
import UIKit

@objc(SafeAreasColorPlugin)
public class SafeAreasColorPlugin: CAPPlugin, CAPBridgedPlugin {
public let identifier = "SafeAreasColorPlugin"
public let jsName = "SafeAreasColor"
public let pluginMethods: [CAPPluginMethod] = [
CAPPluginMethod(name: "changeSafeAreasColorOniOS", returnType: CAPPluginReturnPromise)
]

@objc func changeSafeAreasColorOniOS(_ call: CAPPluginCall) {
let value = call.getString("color") ?? ""
guard let uiColor = UIColor(hex: value) else {
call.reject("Invalid color format")
return
}

DispatchQueue.main.async {
if #available(iOS 13.0, *) {
// Find the active window in iOS 13 or later
if let window = UIApplication.shared.connectedScenes
.compactMap({ $0 as? UIWindowScene })
.flatMap({ $0.windows })
.first(where: { $0.isKeyWindow }) {

window.backgroundColor = uiColor // Set the background color
call.resolve(["value": "Color set successfully"])
} else {
call.reject("No active window found")
}
} else {
// For iOS 12 and earlier
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we don't support 12 and earlier, our version minimum atm is 16 - latest iOS is 18

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did this condition based on code made for cut Safe Areas. So remove this condition from there as well?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can keep it if you want, just saying that since we only support iOS 16 and above the code is not being used

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you are correct, if both are dead code, they should be removed to not have unnecessary code.

And the condition is using 13.0, we can increase this number to 16 as well.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sounds good

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed

if let window = UIApplication.shared.keyWindow {
window.backgroundColor = uiColor
call.resolve(["value": "Color set successfully"])
} else {
call.reject("No key window found")
}
}
}

call.resolve(["value": value])
}
}

extension UIColor {
convenience init?(hex: String) {
var hexSanitized = hex.trimmingCharacters(in: .whitespacesAndNewlines).uppercased()

if hexSanitized.hasPrefix("#") {
hexSanitized.remove(at: hexSanitized.startIndex)
}

var rgb: UInt64 = 0
guard Scanner(string: hexSanitized).scanHexInt64(&rgb) else { return nil }

let length = hexSanitized.count
switch length {
case 6: // RGB
self.init(
red: CGFloat((rgb & 0xFF0000) >> 16) / 255.0,
green: CGFloat((rgb & 0x00FF00) >> 8) / 255.0,
blue: CGFloat(rgb & 0x0000FF) / 255.0,
alpha: 1.0
)
case 8: // RGBA
self.init(
red: CGFloat((rgb & 0xFF000000) >> 24) / 255.0,
green: CGFloat((rgb & 0x00FF0000) >> 16) / 255.0,
blue: CGFloat((rgb & 0x0000FF00) >> 8) / 255.0,
alpha: CGFloat(rgb & 0x000000FF) / 255.0
)
default:
return nil
}
}
}
4 changes: 4 additions & 0 deletions ios/App/PluginViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ import UIKit
import Capacitor

class PluginViewController: CAPBridgeViewController {
override open func capacitorDidLoad() {
bridge?.registerPluginInstance(SafeAreasColorPlugin())
}

override open func viewDidLoad() {
super.viewDidLoad()

Expand Down
1 change: 1 addition & 0 deletions ios/App/Podfile
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ def capacitor_pods
pod 'CapacitorKeyboard', :path => '../../node_modules/@capacitor/keyboard'
pod 'CapacitorScreenOrientation', :path => '../../node_modules/@capacitor/screen-orientation'
pod 'CapacitorSplashScreen', :path => '../../node_modules/@capacitor/splash-screen'
pod 'CapacitorStatusBar', :path => '../../node_modules/@capacitor/status-bar'
end

target 'App' do
Expand Down
8 changes: 7 additions & 1 deletion ios/App/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ PODS:
- Capacitor
- CapacitorSplashScreen (6.0.2):
- Capacitor
- CapacitorStatusBar (6.0.2):
- Capacitor

DEPENDENCIES:
- "Capacitor (from `../../node_modules/@capacitor/ios`)"
Expand All @@ -27,6 +29,7 @@ DEPENDENCIES:
- "CapacitorKeyboard (from `../../node_modules/@capacitor/keyboard`)"
- "CapacitorScreenOrientation (from `../../node_modules/@capacitor/screen-orientation`)"
- "CapacitorSplashScreen (from `../../node_modules/@capacitor/splash-screen`)"
- "CapacitorStatusBar (from `../../node_modules/@capacitor/status-bar`)"

EXTERNAL SOURCES:
Capacitor:
Expand All @@ -47,6 +50,8 @@ EXTERNAL SOURCES:
:path: "../../node_modules/@capacitor/screen-orientation"
CapacitorSplashScreen:
:path: "../../node_modules/@capacitor/splash-screen"
CapacitorStatusBar:
:path: "../../node_modules/@capacitor/status-bar"

SPEC CHECKSUMS:
Capacitor: 1f3c7b9802d958cd8c4eb63895fff85dff2e1eea
Expand All @@ -58,7 +63,8 @@ SPEC CHECKSUMS:
CapacitorKeyboard: 460c6f9ec5e52c84f2742d5ce2e67bbc7ab0ebb0
CapacitorScreenOrientation: 3bb823f5d265190301cdc5d58a568a287d98972a
CapacitorSplashScreen: 250df9ef8014fac5c7c1fd231f0f8b1d8f0b5624
CapacitorStatusBar: 3b9ac7d0684770522c532d1158a1434512ab1477

PODFILE CHECKSUM: 0bfaa008b5f31bb57606a8c6259197a6af507ba4
PODFILE CHECKSUM: 97c46b79f9ec807c302bf24e1511e3e277306740

COCOAPODS: 1.16.2
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
"@capacitor/keyboard": "^6.0.3",
"@capacitor/screen-orientation": "^6.0.3",
"@capacitor/splash-screen": "^6.0.2",
"@capacitor/status-bar": "^6.0.2",
"@dicebear/collection": "^9.0.1",
"@dicebear/core": "^9.0.1",
"@dicebear/identicon": "^9.0.1",
Expand Down
11 changes: 11 additions & 0 deletions src/lib/plugins/safeAreaColorAndroid.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { log } from "$lib/utils/Logger"
import { registerPlugin } from "@capacitor/core"
import { StatusBar, Style } from "@capacitor/status-bar"

interface ISafeAreaColorPlugin {
setStatusBarColor(options: { color: string }): Promise<{ value: string }>
Expand All @@ -11,6 +12,16 @@ const SafeAreaColorPlugin = registerPlugin<ISafeAreaColorPlugin>("SafeAreaColorP
async function setStatusBarColor(color: string) {
try {
log.info("Calling native android function to change status bar color")
if (color.toLowerCase() === "white") {
color = "#FFFFFF"
log.info(`Converted color "white" to hexadecimal: ${color}`)
await StatusBar.setStyle({ style: Style.Light })
log.debug("Change status bar style to light")
} else {
await StatusBar.setStyle({ style: Style.Dark })
log.debug("Change status bar style to dark")
}

await SafeAreaColorPlugin.setStatusBarColor({ color })
} catch (error) {
log.error("Error setting status bar color:", error)
Expand Down
34 changes: 34 additions & 0 deletions src/lib/plugins/safeAreaColoriOS.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { log } from "$lib/utils/Logger"
import { registerPlugin } from "@capacitor/core"
import { StatusBar, Style } from "@capacitor/status-bar"

interface ISafeAreasColorPlugin {
changeSafeAreasColorOniOS(options: { color: string }): Promise<{ value: string }>
}

const Echo = registerPlugin<ISafeAreasColorPlugin>("SafeAreasColor")

async function setNewSafeAreasColorOniOS(color: string) {
try {
log.info("Calling native iOS function to change status bar color")

// Check if the color is 'white' and convert to hex
if (color.toLowerCase() === "white") {
color = "#FFFFFF"
log.info(`Converted color "white" to hexadecimal: ${color}`)
await StatusBar.setStyle({ style: Style.Light })
log.debug("Change status bar style to light")
} else {
await StatusBar.setStyle({ style: Style.Dark })
log.debug("Change status bar style to dark")
}

await Echo.changeSafeAreasColorOniOS({ color })
} catch (error) {
log.error("Error trying to call swift function:", error)
}
}

export function changeSafeAreaColorsOniOS(color: string) {
setNewSafeAreasColorOniOS(color)
}
8 changes: 8 additions & 0 deletions src/lib/utils/Mobile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,11 @@ export function isAndroid(): boolean {
}
return platform === "android"
}

export function isiOSMobile(): boolean {
if (platform === null) {
log.warn("Platform info not yet loaded. Assuming 'false'.")
return false
}
return platform === "ios"
}
12 changes: 8 additions & 4 deletions src/routes/+layout.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,9 @@
import Market from "$lib/components/market/Market.svelte"
import { swipe } from "$lib/components/ui/Swipe"
import { ScreenOrientation } from "@capacitor/screen-orientation"
import { fetchDeviceInfo, isAndroid, isAndroidOriOS } from "$lib/utils/Mobile"
import { fetchDeviceInfo, isAndroid, isAndroidOriOS, isiOSMobile } from "$lib/utils/Mobile"
import { changeSafeAreaColorsOnAndroid } from "$lib/plugins/safeAreaColorAndroid"
import { changeSafeAreaColorsOniOS } from "$lib/plugins/safeAreaColoriOS"

log.debug("Initializing app, layout routes page.")

Expand Down Expand Up @@ -230,11 +231,14 @@

function changeSafeAreaColors() {
setTimeout(() => {
const rootStyles = getComputedStyle(document.documentElement)
let mainBgColor = rootStyles.getPropertyValue("--background").trim()
if (isAndroid()) {
const rootStyles = getComputedStyle(document.documentElement)
let mainBgColor = rootStyles.getPropertyValue("--background").trim()
changeSafeAreaColorsOnAndroid(mainBgColor)
}
if (isiOSMobile()) {
changeSafeAreaColorsOniOS(mainBgColor)
}
}, 1000)
}

Expand Down Expand Up @@ -289,7 +293,7 @@

onMount(async () => {
await fetchDeviceInfo()
if (await isAndroidOriOS()) {
if (isAndroidOriOS()) {
lockOrientation()
}

Expand Down
Loading