Skip to main content

smbcloud_ascapi_aso/
app_screenshot_set.rs

1//! An `AppScreenshotSet` groups the screenshots for one device/display
2//! class (e.g. Apple Vision Pro, iPhone 6.7") within one localization of an
3//! `AppStoreVersion`. Screenshots themselves are a separate resource
4//! ([`crate::app_screenshot`]) that belongs to a set.
5
6use async_trait::async_trait;
7use reqwest::Method;
8use serde::{Deserialize, Serialize};
9use smbcloud_ascapi_core::jsonapi::{
10    CreateBody, CreateData, Document, Resource, ResourceId, ToOne,
11};
12use smbcloud_ascapi_core::Client;
13use smbcloud_ascapi_core::Result;
14
15pub const RESOURCE_TYPE: &str = "appScreenshotSets";
16
17/// The device/display class a screenshot set targets. Apple documents the
18/// full set at
19/// <https://developer.apple.com/documentation/appstoreconnectapi/screenshotdisplaytype>;
20/// this covers the App Store (non-iMessage) display classes in current use.
21#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
22pub enum ScreenshotDisplayType {
23    #[serde(rename = "APP_APPLE_VISION_PRO")]
24    AppleVisionPro,
25    #[serde(rename = "APP_IPHONE_67")]
26    Iphone67,
27    #[serde(rename = "APP_IPHONE_65")]
28    Iphone65,
29    #[serde(rename = "APP_IPHONE_61")]
30    Iphone61,
31    #[serde(rename = "APP_IPHONE_58")]
32    Iphone58,
33    #[serde(rename = "APP_IPHONE_55")]
34    Iphone55,
35    #[serde(rename = "APP_IPHONE_47")]
36    Iphone47,
37    #[serde(rename = "APP_IPHONE_40")]
38    Iphone40,
39    #[serde(rename = "APP_IPHONE_35")]
40    Iphone35,
41    #[serde(rename = "APP_IPAD_PRO_3GEN_129")]
42    IpadPro3Gen129,
43    #[serde(rename = "APP_IPAD_PRO_3GEN_11")]
44    IpadPro3Gen11,
45    #[serde(rename = "APP_IPAD_PRO_129")]
46    IpadPro129,
47    #[serde(rename = "APP_IPAD_105")]
48    Ipad105,
49    #[serde(rename = "APP_IPAD_97")]
50    Ipad97,
51    #[serde(rename = "APP_DESKTOP")]
52    Desktop,
53    #[serde(rename = "APP_APPLE_TV")]
54    AppleTv,
55    #[serde(rename = "APP_WATCH_ULTRA")]
56    WatchUltra,
57    #[serde(rename = "APP_WATCH_SERIES_10")]
58    WatchSeries10,
59    #[serde(rename = "APP_WATCH_SERIES_7")]
60    WatchSeries7,
61    #[serde(rename = "APP_WATCH_SERIES_4")]
62    WatchSeries4,
63    #[serde(rename = "APP_WATCH_SERIES_3")]
64    WatchSeries3,
65}
66
67#[derive(Debug, Clone, Serialize, Deserialize)]
68#[serde(rename_all = "camelCase")]
69pub struct AppScreenshotSetAttributes {
70    pub screenshot_display_type: ScreenshotDisplayType,
71}
72
73pub type AppScreenshotSet = Resource<AppScreenshotSetAttributes>;
74
75#[derive(Debug, Clone, Serialize)]
76#[serde(rename_all = "camelCase")]
77pub struct AppScreenshotSetCreateAttributes {
78    pub screenshot_display_type: ScreenshotDisplayType,
79}
80
81#[derive(Debug, Clone, Serialize)]
82#[serde(rename_all = "camelCase")]
83pub struct AppScreenshotSetRelationships {
84    pub app_store_version_localization: ToOne,
85}
86
87/// Per-device-class screenshot buckets.
88///
89/// An extension trait rather than inherent methods, because `Client`
90/// lives in the core crate and Rust only allows inherent impls in the
91/// crate that defines the type. Import it, or the crate's `prelude`,
92/// to call these on a `Client`.
93#[async_trait]
94pub trait AppScreenshotSetsApi {
95    /// `GET /v1/appStoreVersionLocalizations/{id}/appScreenshotSets`.
96    async fn list_app_screenshot_sets(
97        &self,
98        app_store_version_localization_id: &str,
99    ) -> Result<Vec<AppScreenshotSet>>;
100
101    /// `POST /v1/appScreenshotSets` — adds a device/display class's
102    /// screenshot bucket to a localization. Screenshots are then added to
103    /// the returned set with [`AppScreenshotsApi::create_app_screenshot`](crate::app_screenshot::AppScreenshotsApi::create_app_screenshot) /
104    /// [`AppScreenshotsApi::upload_app_screenshot`](crate::app_screenshot::AppScreenshotsApi::upload_app_screenshot).
105    async fn create_app_screenshot_set(
106        &self,
107        app_store_version_localization_id: &str,
108        attributes: AppScreenshotSetCreateAttributes,
109    ) -> Result<AppScreenshotSet>;
110
111    /// `DELETE /v1/appScreenshotSets/{id}`.
112    async fn delete_app_screenshot_set(&self, id: &str) -> Result<()>;
113}
114
115#[async_trait]
116impl AppScreenshotSetsApi for Client {
117    async fn list_app_screenshot_sets(
118        &self,
119        app_store_version_localization_id: &str,
120    ) -> Result<Vec<AppScreenshotSet>> {
121        let path = format!(
122            "/v1/appStoreVersionLocalizations/{app_store_version_localization_id}/appScreenshotSets"
123        );
124        self.list_all::<AppScreenshotSetAttributes>(&path, &[])
125            .await
126    }
127
128    async fn create_app_screenshot_set(
129        &self,
130        app_store_version_localization_id: &str,
131        attributes: AppScreenshotSetCreateAttributes,
132    ) -> Result<AppScreenshotSet> {
133        let body = CreateBody {
134            data: CreateData {
135                resource_type: RESOURCE_TYPE,
136                attributes,
137                relationships: Some(AppScreenshotSetRelationships {
138                    app_store_version_localization: ToOne {
139                        data: ResourceId {
140                            resource_type: crate::app_store_version_localization::RESOURCE_TYPE,
141                            id: app_store_version_localization_id.to_string(),
142                        },
143                    },
144                }),
145            },
146        };
147        let doc: Document<AppScreenshotSetAttributes> = self
148            .request(Method::POST, "/v1/appScreenshotSets", &[], Some(&body))
149            .await?;
150        Ok(doc.data)
151    }
152
153    async fn delete_app_screenshot_set(&self, id: &str) -> Result<()> {
154        let path = format!("/v1/appScreenshotSets/{id}");
155        self.request_no_content::<()>(Method::DELETE, &path, &[], None)
156            .await
157    }
158}