Skip to content

Commit

Permalink
Update
Browse files Browse the repository at this point in the history
  • Loading branch information
aromanov91 committed Dec 25, 2024
1 parent 343fec6 commit 9e0d8a6
Show file tree
Hide file tree
Showing 8 changed files with 448 additions and 49 deletions.
33 changes: 29 additions & 4 deletions Sources/OversizeAppStoreServices/Models/App.swift
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,7 @@ public struct App: Identifiable, Sendable {
self.included = Included(
appStoreVersions: appStoreVersions.compactMap { appStoreVersion in
.init(
schema: appStoreVersion,
builds: []
schema: appStoreVersion
)
},
builds: builds.compactMap { .init(schema: $0) }.sorted(by: { $0.uploadedDate > $1.uploadedDate }),
Expand Down Expand Up @@ -146,8 +145,7 @@ public struct App: Identifiable, Sendable {
self.included = Included(
appStoreVersions: appStoreVersions.compactMap { appStoreVersion in
.init(
schema: appStoreVersion,
builds: []
schema: appStoreVersion
)
},
builds: builds.compactMap { .init(schema: $0) }.sorted(by: { $0.uploadedDate > $1.uploadedDate }),
Expand Down Expand Up @@ -184,5 +182,32 @@ public extension App {
public var visionOsAppStoreVersions: [AppStoreVersion] {
appStoreVersions.filter { $0.platform == .visionOs }
}

public var appStoreVersionsPlatforms: [Platform] {
var platforms: [Platform] = []

if !macOsAppStoreVersions.isEmpty {
platforms.append(.macOs)
}
if !iOsAppStoreVersions.isEmpty {
platforms.append(.ios)
}
if !tvOsAppStoreVersions.isEmpty {
platforms.append(.tvOs)
}
if !visionOsAppStoreVersions.isEmpty {
platforms.append(.visionOs)
}

return platforms
}
}

var firstNamePath: String {
name.components(separatedBy: [".", "-", ""]).first ?? ""
}

var lastNamePath: String {
name.components(separatedBy: [".", "-", ""]).last ?? ""
}
}
59 changes: 47 additions & 12 deletions Sources/OversizeAppStoreServices/Models/AppStoreVersion.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,9 @@ public struct AppStoreVersion: Sendable, Identifiable {
public let createdDate: Date?

public let included: Included?
public let relationships: Relationships?

init?(schema: AppStoreAPI.AppStoreVersion, builds: [AppStoreAPI.Build] = []) {
init?(schema: AppStoreAPI.AppStoreVersion, included: [AppStoreAPI.AppStoreVersionsResponse.IncludedItem]? = nil) {
guard let storeState = schema.attributes?.appStoreState?.rawValue,
let storeStateType: AppStoreVersionState = .init(rawValue: storeState),
let state = schema.attributes?.appVersionState?.rawValue,
Expand All @@ -44,22 +45,56 @@ public struct AppStoreVersion: Sendable, Identifiable {
reviewType = .init(rawValue: schema.attributes?.createdDate?.rawValue ?? "")
releaseType = .init(rawValue: schema.attributes?.releaseType?.rawValue ?? "")

if let build = builds.first(where: { $0.id == schema.relationships?.build?.data?.id ?? "" }) {
included = .init(
builds: builds.compactMap { .init(schema: $0) }.sorted(by: { $0.uploadedDate > $1.uploadedDate }),
build: .init(schema: build)
)
var includedApp: AppStoreAPI.App?
var includedAgeRatingDeclaration: AppStoreAPI.AgeRatingDeclaration?
var includedAppStoreVersionLocalizations: [AppStoreAPI.AppStoreVersionLocalization]?
var includedBuild: AppStoreAPI.Build?
var includedAppStoreReviewDetail: [AppStoreAPI.AppStoreReviewDetail]?

} else {
included = .init(
builds: builds.compactMap { .init(schema: $0) }.sorted(by: { $0.uploadedDate > $1.uploadedDate }),
build: nil
)
if let includedItems = included {
for includedItem in includedItems {
switch includedItem {
case let .app(app):
includedApp = app
case let .ageRatingDeclaration(ageRatingDeclaration):
includedAgeRatingDeclaration = ageRatingDeclaration
case let .appStoreVersionLocalization(appStoreVersionLocalization):
includedAppStoreVersionLocalizations?.append(appStoreVersionLocalization)
case let .build(build):
includedBuild = build
case let .appStoreReviewDetail(appStoreReviewDetail):
includedAppStoreReviewDetail?.append(appStoreReviewDetail)
default: continue
}
}
}

self.included = Included(
app: includedApp.flatMap { .init(schema: $0) },
build: includedBuild.flatMap { .init(schema: $0) },
ageRatingDeclaration: includedAgeRatingDeclaration.flatMap { .init(schema: $0) },
appStoreVersionLocalizations: includedAppStoreVersionLocalizations.flatMap { localizations in
localizations.flatMap(AppStoreVersionLocalization.init)
},
appStoreReviewDetail: includedAppStoreReviewDetail.flatMap { reviewDetails in
reviewDetails.flatMap(AppStoreReviewDetail.init)
}
)

relationships = .init(
appStoreVersionLocalizationsIds: schema.relationships?.appStoreVersionLocalizations?.data?.compactMap { $0.id }
)
}

public struct Included: Sendable {
public let builds: [Build]
public let app: App?
public let build: Build?
public let ageRatingDeclaration: AgeRatingDeclaration?
public let appStoreVersionLocalizations: [AppStoreVersionLocalization]?
public let appStoreReviewDetail: [AppStoreReviewDetail]?
}

public struct Relationships: Sendable {
public let appStoreVersionLocalizationsIds: [String]?
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -93,4 +93,48 @@ public enum AppStoreLanguage: String, CaseIterable, Codable, Sendable, Identifia
case .vietnamese: "Vietnamese"
}
}

public var flagEmoji: String {
switch self {
case .arabic: "🇸🇦"
case .catalan: "🇪🇸"
case .chineseSimplified, .chineseTraditional: "🇨🇳"
case .croatian: "🇭🇷"
case .czech: "🇨🇿"
case .danish: "🇩🇰"
case .dutch: "🇳🇱"
case .englishUS: "🇺🇸"
case .englishAUS: "🇦🇺"
case .englishCAN: "🇨🇦"
case .englishUK: "🇬🇧"
case .finnish: "🇫🇮"
case .french: "🇫🇷"
case .frenchCAN: "🇨🇦"
case .german: "🇩🇪"
case .greek: "🇬🇷"
case .hebrew: "🇮🇱"
case .hindi: "🇮🇳"
case .hungarian: "🇭🇺"
case .indonesian: "🇮🇩"
case .italian: "🇮🇹"
case .japanese: "🇯🇵"
case .korean: "🇰🇷"
case .malay: "🇲🇾"
case .macedonian: "🇲🇰"
case .norwegian: "🇳🇴"
case .polish: "🇵🇱"
case .portuguese: "🇵🇹"
case .portugueseBRA: "🇧🇷"
case .romanian: "🇷🇴"
case .russian: "🇷🇺"
case .slovak: "🇸🇰"
case .spanish: "🇪🇸"
case .spanishMEX: "🇲🇽"
case .swedish: "🇸🇪"
case .thai: "🇹🇭"
case .turkish: "🇹🇷"
case .ukrainian: "🇺🇦"
case .vietnamese: "🇻🇳"
}
}
}
195 changes: 195 additions & 0 deletions Sources/OversizeAppStoreServices/Models/XcodeMetrics.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
import AppStoreAPI
import AppStoreConnect
import Foundation

public struct LocalXcodeMetrics: Codable, Equatable, Sendable {
public let version: String?
public let insights: LocalInsights?
public let productData: [LocalProductData]?

public init(dto: XcodeMetrics) {
version = dto.version
insights = dto.insights.map { LocalInsights(dto: $0) }
productData = dto.productData?.map { LocalProductData(dto: $0) }
}
}

// MARK: - Insights

public struct LocalInsights: Codable, Equatable, Sendable {
public let trendingUp: [LocalMetricsInsight]?
public let regressions: [LocalMetricsInsight]?

public init(dto: XcodeMetrics.Insights) {
trendingUp = dto.trendingUp?.map { LocalMetricsInsight(dto: $0) }
regressions = dto.regressions?.map { LocalMetricsInsight(dto: $0) }
}
}

// MARK: - Product Data

public struct LocalProductData: Codable, Equatable, Sendable {
public let platform: String?
public let metricCategories: [LocalMetricCategory]?

public init(dto: XcodeMetrics.ProductDatum) {
platform = dto.platform
metricCategories = dto.metricCategories?.map { LocalMetricCategory(dto: $0) }
}
}

// MARK: - Metric Category

public struct LocalMetricCategory: Codable, Equatable, Sendable {
public let identifier: String?
public let metrics: [LocalMetric]?

public init(dto: XcodeMetrics.ProductDatum.MetricCategory) {
identifier = dto.identifier?.rawValue
metrics = dto.metrics?.map { LocalMetric(dto: $0) }
}
}

// MARK: - Metric

public struct LocalMetric: Codable, Equatable, Sendable {
public let identifier: String?
public let goalKeys: [LocalGoalKey]?
public let unit: LocalUnit?
public let datasets: [LocalDataset]?

public init(dto: XcodeMetrics.ProductDatum.MetricCategory.Metric) {
identifier = dto.identifier
goalKeys = dto.goalKeys?.map { LocalGoalKey(dto: $0) }
unit = dto.unit.map { LocalUnit(dto: $0) }
datasets = dto.datasets?.map { LocalDataset(dto: $0) }
}
}

// MARK: - Goal Key

public struct LocalGoalKey: Codable, Equatable, Sendable {
public let goalKey: String?
public let lowerBound: Int?
public let upperBound: Int?

public init(dto: XcodeMetrics.ProductDatum.MetricCategory.Metric.GoalKey) {
goalKey = dto.goalKey
lowerBound = dto.lowerBound
upperBound = dto.upperBound
}
}

// MARK: - Unit

public struct LocalUnit: Codable, Equatable, Sendable {
public let identifier: String?
public let displayName: String?

public init(dto: XcodeMetrics.ProductDatum.MetricCategory.Metric.Unit) {
identifier = dto.identifier
displayName = dto.displayName
}
}

// MARK: - Dataset

public struct LocalDataset: Codable, Equatable, Sendable {
public let filterCriteria: LocalFilterCriteria?
public let points: [LocalPoint]?

public init(dto: XcodeMetrics.ProductDatum.MetricCategory.Metric.Dataset) {
filterCriteria = dto.filterCriteria.map { LocalFilterCriteria(dto: $0) }
points = dto.points?.map { LocalPoint(dto: $0) }
}
}

// MARK: - Filter Criteria

public struct LocalFilterCriteria: Codable, Equatable, Sendable {
public let percentile: String?
public let device: String?
public let deviceMarketingName: String?

public init(dto: XcodeMetrics.ProductDatum.MetricCategory.Metric.Dataset.FilterCriteria) {
percentile = dto.percentile
device = dto.device
deviceMarketingName = dto.deviceMarketingName
}
}

// MARK: - Point

public struct LocalPoint: Codable, Equatable, Sendable {
public let version: String?
public let value: Double?
public let errorMargin: Double?
public let percentageBreakdown: LocalPercentageBreakdown?
public let goal: String?

public init(dto: XcodeMetrics.ProductDatum.MetricCategory.Metric.Dataset.Point) {
version = dto.version
value = dto.value
errorMargin = dto.errorMargin
percentageBreakdown = dto.percentageBreakdown.map { LocalPercentageBreakdown(dto: $0) }
goal = dto.goal
}
}

// MARK: - Percentage Breakdown

public struct LocalPercentageBreakdown: Codable, Equatable, Sendable {
public let value: Double?
public let subSystemLabel: String?

public init(dto: XcodeMetrics.ProductDatum.MetricCategory.Metric.Dataset.Point.PercentageBreakdown) {
value = dto.value
subSystemLabel = dto.subSystemLabel
}
}

// MARK: - Metrics Insight

public struct LocalMetricsInsight: Codable, Equatable, Sendable {
public let metricCategory: String?
public let latestVersion: String?
public let metric: String?
public let summaryString: String?
public let referenceVersions: String?
public let maxLatestVersionValue: Double?
public let subSystemLabel: String?
public let isHighImpact: Bool?
public let populations: [LocalPopulation]?

public init(dto: MetricsInsight) {
metricCategory = dto.metricCategory?.rawValue
latestVersion = dto.latestVersion
metric = dto.metric
summaryString = dto.summaryString
referenceVersions = dto.referenceVersions
maxLatestVersionValue = dto.maxLatestVersionValue
subSystemLabel = dto.subSystemLabel
isHighImpact = dto.isHighImpact
populations = dto.populations?.map { LocalPopulation(dto: $0) }
}
}

// MARK: - Population

public struct LocalPopulation: Codable, Equatable, Sendable {
public let deltaPercentage: Double?
public let percentile: String?
public let summaryString: String?
public let referenceAverageValue: Double?
public let latestVersionValue: Double?
public let device: String?

public init(dto: MetricsInsight.Population) {
deltaPercentage = dto.deltaPercentage
percentile = dto.percentile
summaryString = dto.summaryString
referenceAverageValue = dto.referenceAverageValue
latestVersionValue = dto.latestVersionValue
device = dto.device
}
}
4 changes: 4 additions & 0 deletions Sources/OversizeAppStoreServices/ServiceRegistering.swift
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,8 @@ public extension Container {
var cacheService: Factory<CacheService> {
self { CacheService() }
}

var perfPowerMetricsService: Factory<PerfPowerMetricsService> {
self { PerfPowerMetricsService() }
}
}
Loading

0 comments on commit 9e0d8a6

Please sign in to comment.