diff --git a/PresentationLayer/Constants/ColorEnum.swift b/PresentationLayer/Constants/ColorEnum.swift index d146771c1..9438ea745 100644 --- a/PresentationLayer/Constants/ColorEnum.swift +++ b/PresentationLayer/Constants/ColorEnum.swift @@ -67,6 +67,8 @@ public enum ColorEnum: String { case betaRewardsPrimary case correctionRewardsFill case correctionRewardsPrimary + case troRewardsFill + case troRewardsPrimary case lastRun case tooltip case textDarkStable diff --git a/PresentationLayer/Extensions/DomainExtensions/BoostCode+.swift b/PresentationLayer/Extensions/DomainExtensions/BoostCode+.swift index e4fdf7351..9d2575310 100644 --- a/PresentationLayer/Extensions/DomainExtensions/BoostCode+.swift +++ b/PresentationLayer/Extensions/DomainExtensions/BoostCode+.swift @@ -13,6 +13,8 @@ extension BoostCode { switch self { case .betaReward: return LocalizableString.RewardAnalytics.beta.localized + case .trov2: + return LocalizableString.RewardAnalytics.rollouts.localized case .correction: return LocalizableString.RewardAnalytics.compensation.localized case .unknown: @@ -24,6 +26,8 @@ extension BoostCode { switch self { case .betaReward: return .betaRewardsPrimary + case .trov2: + return .troRewardsPrimary case .correction: return .correctionRewardsPrimary case .unknown: @@ -35,6 +39,8 @@ extension BoostCode { switch self { case .betaReward: return .betaRewardsFill + case .trov2: + return .troRewardsFill case .correction: return .correctionRewardsFill case .unknown: @@ -46,6 +52,8 @@ extension BoostCode { switch self { case .betaReward: return .betaRewardsPrimary + case .trov2: + return .troRewardsPrimary case .correction: return .correctionRewardsFill case .unknown: @@ -57,6 +65,8 @@ extension BoostCode { switch self { case .betaReward: return LocalizableString.RewardAnalytics.betaRewards.localized + case .trov2: + return LocalizableString.RewardAnalytics.rolloutsRewards.localized case .correction: return LocalizableString.RewardAnalytics.compensationRewards.localized case .unknown: diff --git a/PresentationLayer/UIComponents/Screens/DailyRewards/Components/BoostsView.swift b/PresentationLayer/UIComponents/Screens/DailyRewards/Components/BoostsView.swift index 5f3d06ce8..16bc46295 100644 --- a/PresentationLayer/UIComponents/Screens/DailyRewards/Components/BoostsView.swift +++ b/PresentationLayer/UIComponents/Screens/DailyRewards/Components/BoostsView.swift @@ -22,9 +22,14 @@ struct BoostsView: View { .foregroundColor(Color(colorEnum: .textWhite)) Spacer() - Text("+ \(rewards.toWXMTokenPrecisionString) \(StringConstants.wxmCurrency)") - .font(.system(size: CGFloat(.caption), weight: .medium)) - .foregroundColor(Color(colorEnum: .textWhite)) + HStack(spacing: CGFloat(.minimumSpacing)) { + Text(LocalizableString.RewardDetails.boostSeeDetails.localized) + .font(.system(size: CGFloat(.caption))) + + Text(FontIcon.chevronRight.rawValue) + .font(.fontAwesome(font: .FAPro, size: CGFloat(.caption))) + } + .foregroundStyle(Color(colorEnum: .textWhite)) } HStack { @@ -34,6 +39,14 @@ struct BoostsView: View { Spacer() } + + HStack { + Text("+ \(rewards.toWXMTokenPrecisionString) \(StringConstants.wxmCurrency)") + .font(.system(size: CGFloat(.caption), weight: .medium)) + .foregroundColor(Color(colorEnum: .textWhite)) + + Spacer() + } } .padding(CGFloat(.defaultSidePadding)) .background { diff --git a/PresentationLayer/UIComponents/Screens/DailyRewards/RewardDetailsViewModel.swift b/PresentationLayer/UIComponents/Screens/DailyRewards/RewardDetailsViewModel.swift index 0a7bef5b5..07053d241 100644 --- a/PresentationLayer/UIComponents/Screens/DailyRewards/RewardDetailsViewModel.swift +++ b/PresentationLayer/UIComponents/Screens/DailyRewards/RewardDetailsViewModel.swift @@ -224,7 +224,7 @@ class RewardDetailsViewModel: ObservableObject { func handleBoostTap(boost: NetworkDeviceRewardDetailsResponse.BoostReward) { switch boost.code { - case .betaReward, .correction: + case .betaReward, .correction, .trov2: let viewModel = ViewModelsFactory.getRewardsBoostViewModel(boost: boost, device: device, date: rewardDetailsResponse?.timestamp) Router.shared.navigateTo(.rewardBoosts(viewModel)) default: diff --git a/PresentationLayer/UIComponents/Screens/RewardBoosts/RewardBoostsView.swift b/PresentationLayer/UIComponents/Screens/RewardBoosts/RewardBoostsView.swift index a50b7be2f..9a7d73bf8 100644 --- a/PresentationLayer/UIComponents/Screens/RewardBoosts/RewardBoostsView.swift +++ b/PresentationLayer/UIComponents/Screens/RewardBoosts/RewardBoostsView.swift @@ -7,6 +7,7 @@ import SwiftUI import Toolkit +import DomainLayer struct RewardBoostsView: View { @StateObject var viewModel: RewardBoostsViewModel @@ -74,14 +75,7 @@ private extension RewardBoostsView { .overlay(Color(colorEnum: .layer2)) } - BoostDetailsView(items: [.init(title: LocalizableString.Boosts.rewardableStationHours.localized, - value: (details.stationHours ?? 0).localizedFormatted), - .init(title: LocalizableString.Boosts.dailyTokensToBeRewarded.localized, - value: "\((details.maxDailyReward ?? 0.0).toWXMTokenPrecisionString) \(StringConstants.wxmCurrency)"), - .init(title: LocalizableString.Boosts.totalTokensToBeRewarded.localized, - value: "\((details.maxTotalReward ?? 0.0).toWXMTokenPrecisionString) \(StringConstants.wxmCurrency)"), - .init(title: LocalizableString.Boosts.boostPeriod.localized, - value: "\(details.boostStartDateString) - \(details.boostStopDateString)")]) + BoostDetailsView(items: getDetailsItems(details: details)) } } } @@ -132,6 +126,30 @@ private extension RewardBoostsView { } .WXMCardStyle() } + + func getDetailsItems(details: NetworkDeviceRewardBoostsResponse.Details) -> [BoostDetailsView.Item] { + var items = [BoostDetailsView.Item]() + + if let stationHours = details.stationHours { + items.append(.init(title: LocalizableString.Boosts.rewardableStationHours.localized, + value: stationHours.localizedFormatted)) + } + + if let maxDailyReward = details.maxDailyReward { + items.append(.init(title: LocalizableString.Boosts.dailyTokensToBeRewarded.localized, + value: "\(maxDailyReward.toWXMTokenPrecisionString) \(StringConstants.wxmCurrency)")) + } + + if let maxTotalReward = details.maxTotalReward { + items.append(.init(title: LocalizableString.Boosts.totalTokensToBeRewarded.localized, + value: "\(maxTotalReward.toWXMTokenPrecisionString) \(StringConstants.wxmCurrency)")) + } + + items.append(.init(title: LocalizableString.Boosts.boostPeriod.localized, + value: "\(details.boostStartDateString) - \(details.boostStopDateString)")) + + return items + } } #Preview { diff --git a/PresentationLayer/UIComponents/Screens/StationRewardDetailsView.swift b/PresentationLayer/UIComponents/Screens/StationRewardDetailsView.swift index 9da1f15b5..dd1a96a4e 100644 --- a/PresentationLayer/UIComponents/Screens/StationRewardDetailsView.swift +++ b/PresentationLayer/UIComponents/Screens/StationRewardDetailsView.swift @@ -22,21 +22,37 @@ struct StationRewardDetailsView: View { Spacer() } - let progress = details.completedPercentage ?? 0 - ProgressView(value: Float(progress), total: 100) - .progressViewStyle(ProgressBarStyle(text: "\(progress)%", - textColor: Color(colorEnum: .textDarkStable), - bgColor: Color(colorEnum: code.primaryColor), - progressColor: Color(colorEnum: code.fillColor))) - .frame(height: 24) + if let progress = details.completedPercentage { + ProgressView(value: Float(progress), total: 100) + .progressViewStyle(ProgressBarStyle(text: "\(progress)%", + textColor: Color(colorEnum: .textDarkStable), + bgColor: Color(colorEnum: code.primaryColor), + progressColor: Color(colorEnum: code.fillColor))) + .frame(height: 24) + } } - BoostDetailsView(items: [.init(title: LocalizableString.RewardAnalytics.totalTokensEarnedSoFar.localized, - value: (details.currentRewards ?? 0).toWXMTokenPrecisionString + " " + StringConstants.wxmCurrency), - .init(title: LocalizableString.Boosts.totalTokensToBeRewarded.localized, - value: (details.totalRewards ?? 0).toWXMTokenPrecisionString + " " + StringConstants.wxmCurrency), - .init(title: LocalizableString.Boosts.boostPeriod.localized, - value: "\(details.boostStartDateString) - \(details.boostStopDateString)")]) + BoostDetailsView(items: boostDetailsItems) } } } + +private extension StationRewardDetailsView { + var boostDetailsItems: [BoostDetailsView.Item] { + var items = [BoostDetailsView.Item]() + if let currentRewards = details.currentRewards { + items.append(.init(title: LocalizableString.RewardAnalytics.totalTokensEarnedSoFar.localized, + value: currentRewards.toWXMTokenPrecisionString + " " + StringConstants.wxmCurrency)) + } + + if let totalRewards = details.totalRewards { + items.append(.init(title: LocalizableString.Boosts.totalTokensToBeRewarded.localized, + value: totalRewards.toWXMTokenPrecisionString + " " + StringConstants.wxmCurrency)) + } + + items.append(.init(title: LocalizableString.Boosts.boostPeriod.localized, + value: "\(details.boostStartDateString) - \(details.boostStopDateString)")) + + return items + } +} diff --git a/wxm-ios/DataLayer/DataLayer/Networking/Mock/Jsons/get_device_rewards_analytics_7d.json b/wxm-ios/DataLayer/DataLayer/Networking/Mock/Jsons/get_device_rewards_analytics_7d.json index 181ea2e71..f9af7b85e 100644 --- a/wxm-ios/DataLayer/DataLayer/Networking/Mock/Jsons/get_device_rewards_analytics_7d.json +++ b/wxm-ios/DataLayer/DataLayer/Networking/Mock/Jsons/get_device_rewards_analytics_7d.json @@ -58,6 +58,11 @@ "type": "boost", "code": "beta_rewards", "value": 1.4353223 + }, + { + "type": "boost", + "code": "trov2", + "value": 1.4353223 } ] }, @@ -78,6 +83,11 @@ "type": "boost", "code": "correction", "value": 1.4353223 + }, + { + "type": "boost", + "code": "trov2", + "value": 0.4353223 } ] }, @@ -93,6 +103,11 @@ "type": "boost", "code": "beta_rewards", "value": 1.4353223 + }, + { + "type": "boost", + "code": "trov2", + "value": 1.2 } ] }, @@ -108,6 +123,11 @@ "type": "boost", "code": "beta_rewards", "value": 1.4353223 + }, + { + "type": "boost", + "code": "trov2", + "value": 0.6353223 } ] } @@ -138,6 +158,12 @@ "boost_period_start": "2025-09-10T00:00:00.000Z", "boost_period_end": "2025-09-11T00:00:00.000Z", "completed_percentage": 100 + }, + { + "code": "trov2", + "type": "TROv2", + "boost_period_start": "2025-09-10T00:00:00.000Z", + "boost_period_end": "2025-09-11T00:00:00.000Z" } ] } diff --git a/wxm-ios/DataLayer/DataLayer/Networking/Mock/Jsons/get_reward_details.json b/wxm-ios/DataLayer/DataLayer/Networking/Mock/Jsons/get_reward_details.json index 91642f5d3..2b947fba1 100644 --- a/wxm-ios/DataLayer/DataLayer/Networking/Mock/Jsons/get_reward_details.json +++ b/wxm-ios/DataLayer/DataLayer/Networking/Mock/Jsons/get_reward_details.json @@ -31,6 +31,15 @@ "actual_reward": 1.23, "reward_score": 50, "max_reward": 2.46 + }, + { + "code": "trov2", + "title": "TROv2 Rewards", + "description": "A reward boost used to distribute additional rewards to TROv2 devices", + "img_url": "https://i0.wp.com/weatherxm.com/wp-content/uploads/2023/12/Home-header-image-1200-x-1200-px-2.png", + "doc_url": "https://docs.weatherxm.com", + "actual_reward": 1.23, + "reward_score": 100 } ] }, diff --git a/wxm-ios/DomainLayer/DomainLayer/Entities/Codables/Me/Network/NetworkDeviceRewardDetailsResponse.swift b/wxm-ios/DomainLayer/DomainLayer/Entities/Codables/Me/Network/NetworkDeviceRewardDetailsResponse.swift index da519a147..c96051eeb 100644 --- a/wxm-ios/DomainLayer/DomainLayer/Entities/Codables/Me/Network/NetworkDeviceRewardDetailsResponse.swift +++ b/wxm-ios/DomainLayer/DomainLayer/Entities/Codables/Me/Network/NetworkDeviceRewardDetailsResponse.swift @@ -114,12 +114,15 @@ public extension NetworkDeviceRewardDetailsResponse { public enum BoostCode: Codable, RawRepresentable, Hashable, Comparable, Sendable { case betaReward case correction(String) + case trov2 case unknown(String) public init?(rawValue: String) { switch rawValue { case "beta_rewards": self = .betaReward + case "trov2": + self = .trov2 case let str where str.hasPrefix("correction"): self = .correction(rawValue) default: @@ -131,6 +134,8 @@ public enum BoostCode: Codable, RawRepresentable, Hashable, Comparable, Sendable switch self { case .betaReward: return "beta_rewards" + case .trov2: + return "trov2" case .correction(let raw): return raw case .unknown(let raw): diff --git a/wxm-ios/Resources/Colors.xcassets/Boosts/Contents.json b/wxm-ios/Resources/Colors.xcassets/Boosts/Contents.json new file mode 100644 index 000000000..73c00596a --- /dev/null +++ b/wxm-ios/Resources/Colors.xcassets/Boosts/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/wxm-ios/Resources/Colors.xcassets/betaRewardsFill.colorset/Contents.json b/wxm-ios/Resources/Colors.xcassets/Boosts/betaRewardsFill.colorset/Contents.json similarity index 100% rename from wxm-ios/Resources/Colors.xcassets/betaRewardsFill.colorset/Contents.json rename to wxm-ios/Resources/Colors.xcassets/Boosts/betaRewardsFill.colorset/Contents.json diff --git a/wxm-ios/Resources/Colors.xcassets/betaRewardsPrimary.colorset/Contents.json b/wxm-ios/Resources/Colors.xcassets/Boosts/betaRewardsPrimary.colorset/Contents.json similarity index 100% rename from wxm-ios/Resources/Colors.xcassets/betaRewardsPrimary.colorset/Contents.json rename to wxm-ios/Resources/Colors.xcassets/Boosts/betaRewardsPrimary.colorset/Contents.json diff --git a/wxm-ios/Resources/Colors.xcassets/correctionRewardsFill.colorset/Contents.json b/wxm-ios/Resources/Colors.xcassets/Boosts/correctionRewardsFill.colorset/Contents.json similarity index 100% rename from wxm-ios/Resources/Colors.xcassets/correctionRewardsFill.colorset/Contents.json rename to wxm-ios/Resources/Colors.xcassets/Boosts/correctionRewardsFill.colorset/Contents.json diff --git a/wxm-ios/Resources/Colors.xcassets/correctionRewardsPrimary.colorset/Contents.json b/wxm-ios/Resources/Colors.xcassets/Boosts/correctionRewardsPrimary.colorset/Contents.json similarity index 100% rename from wxm-ios/Resources/Colors.xcassets/correctionRewardsPrimary.colorset/Contents.json rename to wxm-ios/Resources/Colors.xcassets/Boosts/correctionRewardsPrimary.colorset/Contents.json diff --git a/wxm-ios/Resources/Colors.xcassets/otherRewardChart.colorset/Contents.json b/wxm-ios/Resources/Colors.xcassets/Boosts/otherRewardChart.colorset/Contents.json similarity index 100% rename from wxm-ios/Resources/Colors.xcassets/otherRewardChart.colorset/Contents.json rename to wxm-ios/Resources/Colors.xcassets/Boosts/otherRewardChart.colorset/Contents.json diff --git a/wxm-ios/Resources/Colors.xcassets/otherRewardFill.colorset/Contents.json b/wxm-ios/Resources/Colors.xcassets/Boosts/otherRewardFill.colorset/Contents.json similarity index 100% rename from wxm-ios/Resources/Colors.xcassets/otherRewardFill.colorset/Contents.json rename to wxm-ios/Resources/Colors.xcassets/Boosts/otherRewardFill.colorset/Contents.json diff --git a/wxm-ios/Resources/Colors.xcassets/otherRewardPrimary.colorset/Contents.json b/wxm-ios/Resources/Colors.xcassets/Boosts/otherRewardPrimary.colorset/Contents.json similarity index 100% rename from wxm-ios/Resources/Colors.xcassets/otherRewardPrimary.colorset/Contents.json rename to wxm-ios/Resources/Colors.xcassets/Boosts/otherRewardPrimary.colorset/Contents.json diff --git a/wxm-ios/Resources/Colors.xcassets/Boosts/troRewardsFill.colorset/Contents.json b/wxm-ios/Resources/Colors.xcassets/Boosts/troRewardsFill.colorset/Contents.json new file mode 100644 index 000000000..242723f9c --- /dev/null +++ b/wxm-ios/Resources/Colors.xcassets/Boosts/troRewardsFill.colorset/Contents.json @@ -0,0 +1,20 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x62", + "green" : "0x2F", + "red" : "0xAA" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/wxm-ios/Resources/Colors.xcassets/Boosts/troRewardsPrimary.colorset/Contents.json b/wxm-ios/Resources/Colors.xcassets/Boosts/troRewardsPrimary.colorset/Contents.json new file mode 100644 index 000000000..541e53990 --- /dev/null +++ b/wxm-ios/Resources/Colors.xcassets/Boosts/troRewardsPrimary.colorset/Contents.json @@ -0,0 +1,20 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x80", + "green" : "0x3E", + "red" : "0xDE" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/wxm-ios/Resources/Localizable/Localizable+RewardDetails.swift b/wxm-ios/Resources/Localizable/Localizable+RewardDetails.swift index a85daf257..240a82c4e 100644 --- a/wxm-ios/Resources/Localizable/Localizable+RewardDetails.swift +++ b/wxm-ios/Resources/Localizable/Localizable+RewardDetails.swift @@ -68,6 +68,7 @@ extension LocalizableString { case contactSupportButtonTitle case unhandledBoostMessage case rewardsBoostFailedTitle + case boostSeeDetails } } @@ -229,6 +230,8 @@ extension LocalizableString.RewardDetails: WXMLocalizable { return "reward_details_unhandled_boost_message" case .rewardsBoostFailedTitle: return "reward_details_rewards_boost_failed_title" + case .boostSeeDetails: + return "reward_details_boost_see_details" } } } diff --git a/wxm-ios/Resources/Localizable/Localizable.xcstrings b/wxm-ios/Resources/Localizable/Localizable.xcstrings index 61c178912..dd8f6e543 100644 --- a/wxm-ios/Resources/Localizable/Localizable.xcstrings +++ b/wxm-ios/Resources/Localizable/Localizable.xcstrings @@ -8580,6 +8580,28 @@ } } }, + "reward_analytics_rollouts" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Rollouts" + } + } + } + }, + "reward_analytics_rollouts_rewards" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Rollouts Rewards" + } + } + } + }, "reward_analytics_station_rewards" : { "extractionState" : "manual", "localizations" : { @@ -8679,6 +8701,17 @@ } } }, + "reward_details_boost_see_details" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "See details" + } + } + } + }, "reward_details_cell_position" : { "extractionState" : "manual", "localizations" : { diff --git a/wxm-ios/Resources/Localizable/LocalizableString+RewardAnalytics.swift b/wxm-ios/Resources/Localizable/LocalizableString+RewardAnalytics.swift index 0a135f70d..fcbc5299e 100644 --- a/wxm-ios/Resources/Localizable/LocalizableString+RewardAnalytics.swift +++ b/wxm-ios/Resources/Localizable/LocalizableString+RewardAnalytics.swift @@ -20,6 +20,8 @@ extension LocalizableString { case details(String) case betaRewards case beta + case rollouts + case rolloutsRewards case compensation case compensationRewards case totalTokensEarnedSoFar @@ -74,6 +76,10 @@ extension LocalizableString.RewardAnalytics: WXMLocalizable { return "reward_analytics_beta_rewards" case .beta: return "reward_analytics_beta" + case .rollouts: + return "reward_analytics_rollouts" + case .rolloutsRewards: + return "reward_analytics_rollouts_rewards" case .compensation: return "reward_analytics_compensation" case .compensationRewards: