Skip to content
Draft
Show file tree
Hide file tree
Changes from all 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
15 changes: 14 additions & 1 deletion __mocks__/@ua/react-native-airship.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type {AirshipContact, AirshipPush, AirshipPushAndroid, AirshipPushIOS, AirshipRoot} from '@ua/react-native-airship';
import type {AirshipContact, AirshipLiveActivityManager, AirshipPush, AirshipPushAndroid, AirshipPushIOS, AirshipRoot, AirshipRootIOS} from '@ua/react-native-airship';

// eslint-disable-next-line no-restricted-syntax
enum EventType {
Expand Down Expand Up @@ -69,11 +69,24 @@ const contact = jest.fn().mockImplementation(() => ({
module: jest.fn(),
}))() as AirshipContact;

const liveActivityManager = jest.fn().mockImplementation(() => ({
list: jest.fn(() => Promise.resolve([])),
listAll: jest.fn(() => Promise.resolve([])),
start: jest.fn(() => Promise.resolve({id: 'mock-activity-id'})),
update: jest.fn(() => Promise.resolve()),
end: jest.fn(() => Promise.resolve()),
}))() as AirshipLiveActivityManager;

const airshipIOS = jest.fn().mockImplementation(() => ({
liveActivityManager,
}))() as AirshipRootIOS;

const Airship: Partial<AirshipRoot> = {
addListener: jest.fn(),
removeAllListeners: jest.fn(),
push,
contact,
iOS: airshipIOS,
};

export default Airship;
Expand Down
3 changes: 2 additions & 1 deletion cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -835,7 +835,8 @@
"canvaskit",
"Invoicify",
"UKEU",
"USCA"
"USCA",
"widgetkit"
],
"ignorePaths": [
"src/languages/de.ts",
Expand Down
22 changes: 22 additions & 0 deletions ios/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import ReactAppDependencyProvider
import ExpoModulesCore
import Firebase
import Expo
import ActivityKit
import AirshipFrameworkProxy

@main
class AppDelegate: ExpoAppDelegate, UNUserNotificationCenterDelegate {
Expand Down Expand Up @@ -58,10 +60,30 @@ class AppDelegate: ExpoAppDelegate, UNUserNotificationCenterDelegate {

RNBackgroundTaskManager.setup()

// Register GPS trip Live Activity with Airship
if #available(iOS 16.1, *) {
try? LiveActivityManager.shared.setup { configurator in
await configurator.register(
forType: Activity<GpsTripAttributes>.self,
airshipNameExtractor: nil
)
}
}

return true
}


override func applicationWillTerminate(_ application: UIApplication) {
if #available(iOS 16.2, *) {
for activity in Activity<GpsTripAttributes>.activities {
Task.detached {
await activity.end(nil, dismissalPolicy: .immediate)
}
}
}
}

override func application(_ application: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool {
return RCTLinkingManager.application(application, open: url, options: options)
}
Expand Down
15 changes: 15 additions & 0 deletions ios/LiveActivity/Assets.xcassets/logo.imageset/Contents.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"images" : [
{
"filename" : "logo.svg",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"preserves-vector-representation" : true
}
}
1 change: 1 addition & 0 deletions ios/LiveActivity/Assets.xcassets/logo.imageset/logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"images" : [
{
"filename" : "wordmark.svg",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"preserves-vector-representation" : true
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
13 changes: 13 additions & 0 deletions ios/LiveActivity/GpsTripAttributes.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import ActivityKit

struct GpsTripAttributes: ActivityAttributes {
var deepLink: String
var buttonText: String
var subtitle: String
var distanceUnit: String
var distanceUnitLong: String

public struct ContentState: Codable, Hashable {
var distance: Double
}
}
117 changes: 117 additions & 0 deletions ios/LiveActivity/GpsTripLiveActivity.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
import WidgetKit
import SwiftUI

private extension Color {
static let expensifyGreen = Color(red: 3 / 255, green: 212 / 255, blue: 124 / 255)
}

private func distanceString(distance: Double) -> String {
String(format: "%.1f", distance)
}

private func distanceStringShort(distance: Double, distanceUnit: String) -> String {
String(format: "%.0f\(distanceUnit)", distance)
}

@available(iOS 16.1, *)
struct GpsTripLiveActivity: Widget {
var body: some WidgetConfiguration {
ActivityConfiguration(for: GpsTripAttributes.self) { context in
VStack {
HStack(alignment: .bottom) {
VStack(alignment: .leading, spacing: 14) {
Image("wordmark")
.resizable()
.scaledToFit()
.frame(maxWidth: 64)
Text(context.attributes.subtitle)
.font(.custom("ExpensifyNeue-Regular", size: 15))
.foregroundColor(.white)
}
Spacer()
VStack(alignment: .trailing, spacing: -4) {
Text(distanceString(distance: context.state.distance))
.font(.custom("ExpensifyNeue-Bold", size: 45))
.foregroundColor(.expensifyGreen)
Text(context.attributes.distanceUnitLong)
.font(.custom("ExpensifyNeue-Regular", size: 15))
.foregroundColor(.white)
}
}
}
.padding(.top, 22)
.padding(.bottom, 28)
.padding(.horizontal, 24)
.background {
LinearGradient(
stops: [
.init(color: Color(.sRGB, red: 0, green: 46 / 255, blue: 34 / 255), location: 0),
.init(color: Color(.sRGB, red: 6 / 255, green: 27 / 255, blue: 9 / 255), location: 1),
],
startPoint: UnitPoint(x: 0, y: 0.41),
endPoint: UnitPoint(x: 1, y: 0.59)
)
}
.widgetURL(URL(string: "new-expensify://\(context.attributes.deepLink)"))
} dynamicIsland: { context in
DynamicIsland {
DynamicIslandExpandedRegion(.leading) {
VStack(alignment: .leading, spacing: 14) {
Image("wordmark")
.resizable()
.scaledToFit()
.frame(maxWidth: 64)
Text(context.attributes.subtitle)
.font(.custom("ExpensifyNeue-Regular", size: 15))
.foregroundColor(.white)
.lineLimit(1)
.minimumScaleFactor(0.5)
}
.frame(minHeight: 70, maxHeight: .infinity, alignment: .bottom)
}
DynamicIslandExpandedRegion(.trailing) {
VStack(alignment: .trailing, spacing: -4) {
Text(distanceString(distance: context.state.distance))
.font(.custom("ExpensifyNeue-Bold", size: 45))
.foregroundColor(.expensifyGreen)
.lineLimit(1)
.minimumScaleFactor(0.3)
Text(context.attributes.distanceUnitLong)
.font(.custom("ExpensifyNeue-Regular", size: 15))
.foregroundColor(.white)
}
.frame(minHeight: 70, maxHeight: .infinity, alignment: .bottom)
}
DynamicIslandExpandedRegion(.bottom) {
Text(context.attributes.buttonText)
.font(.custom("ExpensifyNeue-Bold", size: 15))
.foregroundColor(.expensifyGreen)
.frame(maxWidth: .infinity)
.padding(.vertical, 10)
.background(Color.expensifyGreen.opacity(0.2))
.clipShape(Capsule())
.padding(.top, 10)
}
} compactLeading: {
Image("logo")
.resizable()
.scaledToFit()
.frame(maxWidth: 23, maxHeight: 23)
.clipShape(RoundedRectangle(cornerRadius: 7))
} compactTrailing: {
Text(distanceStringShort(distance: context.state.distance, distanceUnit: context.attributes.distanceUnit))
.font(.custom("ExpensifyNeue-Bold", size: 15))
.foregroundColor(.white)
.minimumScaleFactor(0.5)
} minimal: {
Image("logo")
.resizable()
.scaledToFit()
.frame(maxWidth: 23, maxHeight: 23)
.clipShape(RoundedRectangle(cornerRadius: 7))

}
.widgetURL(URL(string: "new-expensify://\(context.attributes.deepLink)"))
}
}
}
11 changes: 11 additions & 0 deletions ios/LiveActivity/GpsTripWidgetBundle.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import WidgetKit
import SwiftUI

@main
struct GpsTripWidgetBundle: WidgetBundle {
var body: some Widget {
if #available(iOS 16.1, *) {
GpsTripLiveActivity()
}
}
}
30 changes: 30 additions & 0 deletions ios/LiveActivity/Info.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDisplayName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundleShortVersionString</key>
<string>9.3.26</string>
<key>CFBundleVersion</key>
<string>9.3.26.4</string>
<key>NSExtension</key>
<dict>
<key>NSExtensionPointIdentifier</key>
<string>com.apple.widgetkit-extension</string>
</dict>
<key>RCTNewArchEnabled</key>
<true/>
<key>UIAppFonts</key>
<array>
<string>ExpensifyNeue-Regular.otf</string>
<string>ExpensifyNeue-Bold.otf</string>
</array>
</dict>
</plist>
10 changes: 10 additions & 0 deletions ios/LiveActivity/LiveActivity.entitlements
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.application-groups</key>
<array>
<string>group.com.expensify.new</string>
</array>
</dict>
</plist>
10 changes: 10 additions & 0 deletions ios/LiveActivityExtension.entitlements
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.application-groups</key>
<array>
<string>group.com.expensify.new</string>
</array>
</dict>
</plist>
Loading
Loading