diff --git a/ios/LiveActivity/Assets.xcassets/location.imageset/Contents.json b/ios/LiveActivity/Assets.xcassets/location.imageset/Contents.json new file mode 100644 index 000000000000..1c2ff97101d9 --- /dev/null +++ b/ios/LiveActivity/Assets.xcassets/location.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "Icon.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/ios/LiveActivity/Assets.xcassets/location.imageset/Icon.svg b/ios/LiveActivity/Assets.xcassets/location.imageset/Icon.svg new file mode 100644 index 000000000000..0940d1d71882 --- /dev/null +++ b/ios/LiveActivity/Assets.xcassets/location.imageset/Icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/ios/LiveActivity/Assets.xcassets/lock-screen-bg.imageset/Contents.json b/ios/LiveActivity/Assets.xcassets/lock-screen-bg.imageset/Contents.json new file mode 100644 index 000000000000..cc95fa65e585 --- /dev/null +++ b/ios/LiveActivity/Assets.xcassets/lock-screen-bg.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "lock-screen-bg.png", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/ios/LiveActivity/Assets.xcassets/lock-screen-bg.imageset/lock-screen-bg.png b/ios/LiveActivity/Assets.xcassets/lock-screen-bg.imageset/lock-screen-bg.png new file mode 100644 index 000000000000..75f80c485ea5 Binary files /dev/null and b/ios/LiveActivity/Assets.xcassets/lock-screen-bg.imageset/lock-screen-bg.png differ diff --git a/ios/LiveActivity/GpsTripAttributes.swift b/ios/LiveActivity/GpsTripAttributes.swift index 6e863e85fb4c..0db8e5d960cc 100644 --- a/ios/LiveActivity/GpsTripAttributes.swift +++ b/ios/LiveActivity/GpsTripAttributes.swift @@ -9,5 +9,7 @@ struct GpsTripAttributes: ActivityAttributes { var distanceUnitLong: String var buttonText: String var subtitle: String + var lockScreenBadgeText: String + var lockScreenTrackingText: String } } diff --git a/ios/LiveActivity/GpsTripLiveActivity.swift b/ios/LiveActivity/GpsTripLiveActivity.swift index 10d9e2ab353b..f8e1ce2ef0ba 100644 --- a/ios/LiveActivity/GpsTripLiveActivity.swift +++ b/ios/LiveActivity/GpsTripLiveActivity.swift @@ -3,6 +3,8 @@ import SwiftUI private extension Color { static let expensifyGreen = Color(red: 3 / 255, green: 212 / 255, blue: 124 / 255) + static let distanceBadgeBg = Color(red: 8 / 255, green: 82 / 255, blue: 57 / 255) + static let brandGreen100 = Color(red: 177 / 255, green: 242 / 255, blue: 214 / 255) } private func distanceString(distance: Double) -> String { @@ -17,40 +19,65 @@ private func distanceStringShort(distance: Double, distanceUnit: String) -> Stri 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.state.subtitle) - .font(.custom("ExpensifyNeue-Regular", size: 15)) - .foregroundColor(.white) - } - Spacer() - VStack(alignment: .trailing, spacing: -4) { + HStack(alignment: .center) { + VStack(alignment: .leading) { + Text(context.state.lockScreenTrackingText) + .font(.custom("ExpensifyNeue-Regular", size: 15)) + .foregroundColor(.brandGreen100) + .kerning(-0.3) + HStack(alignment: .bottom, spacing: 6) { Text(distanceString(distance: context.state.distance)) .font(.custom("ExpensifyNeue-Bold", size: 45)) .foregroundColor(.expensifyGreen) - Text(context.state.distanceUnitLong) - .font(.custom("ExpensifyNeue-Regular", size: 15)) - .foregroundColor(.white) + Text(context.state.distanceUnit) + .font(.custom("ExpensifyNeue-Regular", size: 25)) + .foregroundColor(.brandGreen100) + .padding(.bottom, 5) } } + + Spacer() + + ZStack(alignment: .topTrailing) { + HStack(spacing: 4) { + Image("location") + Text(context.state.lockScreenBadgeText) + .font(.custom("ExpensifyNeue-Bold", size: 11)) + .foregroundColor(.brandGreen100) + } + .padding(.trailing, 10) + .padding(.leading, 8) + .frame(height: 24) + .background(Color.distanceBadgeBg) + .clipShape(Capsule()) + .padding(.trailing, 44) + .offset(y: -8) + + Image("logo") + .resizable() + .scaledToFit() + .frame(width: 60, height: 60) + .clipShape(Circle()) + } } - .padding(.top, 22) - .padding(.bottom, 28) - .padding(.horizontal, 24) + .frame(height: 116) + .padding(.trailing, 28) + .padding(.leading, 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) - ) + ZStack { + 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) + ) + Image("lock-screen-bg") + .resizable() + .scaledToFit() + .frame(maxWidth: .infinity, alignment: .trailing) + } } .widgetURL(URL(string: "new-expensify://\(context.attributes.deepLink)")) } dynamicIsland: { context in @@ -109,7 +136,6 @@ struct GpsTripLiveActivity: Widget { .scaledToFit() .frame(maxWidth: 23, maxHeight: 23) .clipShape(RoundedRectangle(cornerRadius: 7)) - } .widgetURL(URL(string: "new-expensify://\(context.attributes.deepLink)")) } diff --git a/src/languages/de.ts b/src/languages/de.ts index 46ac20d0c7cd..fb19d7447cca 100644 --- a/src/languages/de.ts +++ b/src/languages/de.ts @@ -8298,7 +8298,7 @@ Fügen Sie weitere Ausgabelimits hinzu, um den Cashflow Ihres Unternehmens zu sc prompt: 'Bitte erlaube den Standortzugriff in den Einstellungen deines Geräts, um die GPS‑Streckenverfolgung zu starten.', }, gpsFloatingPillText: 'GPS-Verfolgung läuft...', - liveActivity: {subtitle: 'Entfernungserfassung', button: 'Fortschritt anzeigen'}, + liveActivity: {subtitle: 'Entfernungserfassung', button: 'Fortschritt anzeigen', lockScreenBadgeText: 'Entfernung', lockScreenTrackingText: 'Verfolge …'}, }, reportCardLostOrDamaged: { screenTitle: 'Zeugnis verloren oder beschädigt', diff --git a/src/languages/en.ts b/src/languages/en.ts index 29a0d14f555c..65a4d0cd9f6b 100644 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -8284,6 +8284,8 @@ const translations = { gpsFloatingPillText: 'GPS tracking in progress...', liveActivity: { subtitle: 'Tracking distance', + lockScreenBadgeText: 'Distance', + lockScreenTrackingText: 'Tracking...', button: 'View progress', }, }, diff --git a/src/languages/es.ts b/src/languages/es.ts index f8b418c51c29..ae63254d7683 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -9524,6 +9524,8 @@ ${amount} para ${merchant} - ${date}`, liveActivity: { subtitle: 'Seguimiento de distancia', button: 'Ver progreso', + lockScreenBadgeText: 'Distancia', + lockScreenTrackingText: 'Siguiendo...', }, }, }; diff --git a/src/languages/fr.ts b/src/languages/fr.ts index 9398b551c2e4..cf068a33c5d3 100644 --- a/src/languages/fr.ts +++ b/src/languages/fr.ts @@ -8321,7 +8321,7 @@ Ajoutez davantage de règles de dépenses pour protéger la trésorerie de l’e prompt: 'Veuillez autoriser l’accès à la localisation dans les réglages de votre appareil pour commencer le suivi de distance GPS.', }, gpsFloatingPillText: 'Suivi GPS en cours...', - liveActivity: {subtitle: 'Suivi de la distance', button: 'Voir la progression'}, + liveActivity: {subtitle: 'Suivi de la distance', button: 'Voir la progression', lockScreenBadgeText: 'Distance', lockScreenTrackingText: 'Suivi...'}, }, reportCardLostOrDamaged: { screenTitle: 'relevé de notes perdu ou endommagé', diff --git a/src/languages/it.ts b/src/languages/it.ts index a1a85aa1fb11..e35ab9fb3e8b 100644 --- a/src/languages/it.ts +++ b/src/languages/it.ts @@ -8288,7 +8288,7 @@ Aggiungi altre regole di spesa per proteggere il flusso di cassa aziendale.`, prompt: 'Consenti l’accesso alla posizione nelle impostazioni del dispositivo per iniziare il tracciamento della distanza GPS.', }, gpsFloatingPillText: 'Tracciamento GPS in corso...', - liveActivity: {subtitle: 'Rilevamento distanza', button: 'Visualizza avanzamento'}, + liveActivity: {subtitle: 'Rilevamento distanza', button: 'Visualizza avanzamento', lockScreenBadgeText: 'Distanza', lockScreenTrackingText: 'Tracciamento in corso...'}, }, reportCardLostOrDamaged: { screenTitle: 'Pagella smarrita o danneggiata', diff --git a/src/languages/ja.ts b/src/languages/ja.ts index c3630de5a202..585f295edf4d 100644 --- a/src/languages/ja.ts +++ b/src/languages/ja.ts @@ -8184,7 +8184,7 @@ ${reportName} prompt: 'GPSで距離の追跡を開始するには、端末の設定で位置情報へのアクセスを許可してください。', }, gpsFloatingPillText: 'GPS 追跡を実行中です…', - liveActivity: {subtitle: '距離の記録', button: '進捗を表示'}, + liveActivity: {subtitle: '距離の記録', button: '進捗を表示', lockScreenBadgeText: '距離', lockScreenTrackingText: '追跡中…'}, }, reportCardLostOrDamaged: { screenTitle: '成績表の紛失または破損', diff --git a/src/languages/nl.ts b/src/languages/nl.ts index 043fb84b6c3c..6abefa35954b 100644 --- a/src/languages/nl.ts +++ b/src/languages/nl.ts @@ -8262,7 +8262,7 @@ er bestedingsregels toe om de kasstroom van het bedrijf te beschermen.`, prompt: 'Sta locatiestoegang toe in de instellingen van je apparaat om GPS-afstandsregistratie te starten.', }, gpsFloatingPillText: 'GPS-tracking bezig...', - liveActivity: {subtitle: 'Afstand bijhouden', button: 'Voortgang bekijken'}, + liveActivity: {subtitle: 'Afstand bijhouden', button: 'Voortgang bekijken', lockScreenBadgeText: 'Afstand', lockScreenTrackingText: 'Bezig met bijhouden...'}, }, reportCardLostOrDamaged: { screenTitle: 'Rapportkaart kwijt of beschadigd', diff --git a/src/languages/pl.ts b/src/languages/pl.ts index 8c2c6d443f2a..2c7acfa3b491 100644 --- a/src/languages/pl.ts +++ b/src/languages/pl.ts @@ -8247,7 +8247,7 @@ Dodaj więcej zasad wydatków, żeby chronić płynność finansową firmy.`, prompt: 'Zezwól na dostęp do lokalizacji w ustawieniach urządzenia, aby rozpocząć śledzenie dystansu GPS.', }, gpsFloatingPillText: 'Trwa śledzenie GPS...', - liveActivity: {subtitle: 'Śledzenie dystansu', button: 'Zobacz postęp'}, + liveActivity: {subtitle: 'Śledzenie dystansu', button: 'Zobacz postęp', lockScreenBadgeText: 'Dystans', lockScreenTrackingText: 'Śledzenie...'}, }, reportCardLostOrDamaged: { screenTitle: 'Świadectwo zgubione lub uszkodzone', diff --git a/src/languages/pt-BR.ts b/src/languages/pt-BR.ts index 05e6368b9ab2..726c3ec4b755 100644 --- a/src/languages/pt-BR.ts +++ b/src/languages/pt-BR.ts @@ -8254,7 +8254,7 @@ Adicione mais regras de gasto para proteger o fluxo de caixa da empresa.`, prompt: 'Permita o acesso à localização nas configurações do seu dispositivo para iniciar o rastreamento de distância por GPS.', }, gpsFloatingPillText: 'Rastreamento por GPS em andamento...', - liveActivity: {subtitle: 'Rastreamento de distância', button: 'Ver progresso'}, + liveActivity: {subtitle: 'Rastreamento de distância', button: 'Ver progresso', lockScreenBadgeText: 'Distância', lockScreenTrackingText: 'Rastreando...'}, }, reportCardLostOrDamaged: { screenTitle: 'Boletim perdido ou danificado', diff --git a/src/languages/zh-hans.ts b/src/languages/zh-hans.ts index 22a780fe0e36..03405aca58a9 100644 --- a/src/languages/zh-hans.ts +++ b/src/languages/zh-hans.ts @@ -8044,7 +8044,7 @@ ${reportName} prompt: '请在设备设置中允许访问位置信息,以开始使用 GPS 距离跟踪。', }, gpsFloatingPillText: '正在进行 GPS 跟踪…', - liveActivity: {subtitle: '跟踪距离', button: '查看进度'}, + liveActivity: {subtitle: '跟踪距离', button: '查看进度', lockScreenBadgeText: '距离', lockScreenTrackingText: '正在跟踪…'}, }, reportCardLostOrDamaged: { screenTitle: '成绩单遗失或损坏', diff --git a/src/pages/iou/request/step/IOURequestStepDistanceGPS/GPSNotifications/index.ios.ts b/src/pages/iou/request/step/IOURequestStepDistanceGPS/GPSNotifications/index.ios.ts index 8c1c07976a4c..8bb6f7439f5b 100644 --- a/src/pages/iou/request/step/IOURequestStepDistanceGPS/GPSNotifications/index.ios.ts +++ b/src/pages/iou/request/step/IOURequestStepDistanceGPS/GPSNotifications/index.ios.ts @@ -17,6 +17,8 @@ type GpsLiveActivityState = { buttonText: string; subtitle: string; distanceInMeters: number; + lockScreenBadgeText: string; + lockScreenTrackingText: string; }; let liveActivityState: GpsLiveActivityState | null = null; @@ -36,6 +38,8 @@ function getLiveActivityUpdateState(distance: number, state: GpsLiveActivityStat distanceUnitLong: state.distanceUnitFull, subtitle: state.subtitle, buttonText: state.buttonText, + lockScreenBadgeText: state.lockScreenBadgeText, + lockScreenTrackingText: state.lockScreenTrackingText, }; } @@ -43,6 +47,8 @@ function startGpsTripNotification(translate: LocalizedTranslate, reportID: strin liveActivityState = { subtitle: translate('gps.liveActivity.subtitle'), buttonText: translate('gps.liveActivity.button'), + lockScreenBadgeText: translate('gps.liveActivity.lockScreenBadgeText'), + lockScreenTrackingText: translate('gps.liveActivity.lockScreenTrackingText'), distanceUnit: unit, distanceUnitFull: getDistanceUnitFull(translate, unit), distanceUnitAbbreviated: getDistanceUnitAbbreviated(translate, unit), @@ -126,6 +132,8 @@ function updateGpsTripNotificationLanguage(translate: LocalizedTranslate) { liveActivityState.distanceUnitFull = getDistanceUnitFull(translate, unit); liveActivityState.subtitle = translate('gps.liveActivity.subtitle'); liveActivityState.buttonText = translate('gps.liveActivity.button'); + liveActivityState.lockScreenBadgeText = translate('gps.liveActivity.lockScreenBadgeText'); + liveActivityState.lockScreenTrackingText = translate('gps.liveActivity.lockScreenTrackingText'); const distance = DistanceRequestUtils.convertDistanceUnit(liveActivityState.distanceInMeters, unit);