diff --git a/README.md b/README.md index 85e4eae..45e4b2c 100644 --- a/README.md +++ b/README.md @@ -132,13 +132,14 @@ $activitysmith->notifications->send( ## Live Activities -There are five types of Live Activities: +There are six types of Live Activities: - `stats`: best for showing business numbers side by side, such as revenue, sales, new users, conversion, refunds, or any other value you want visible at a glance - `metrics`: best for live percentage values that change often, like server CPU, memory usage, disk usage, or error rate - `segmented_progress`: best for anything that moves through clear stages, like deployments, onboarding flows, backups, ETL pipelines, migrations, and AI agent runs - `progress`: best for tracking real-time progress with percentage, like tasks, backups, migrations, syncs, or uploads - `alert`: best for status updates, such as feature adoption, reactivation, onboarding blockers, incidents, escalations, and other operational states +- `timer`: best for countdowns and elapsed runtime, like benchmark runs, uploads, backups, transcodes, and long-running jobs ### Start & Update Live Activity @@ -266,6 +267,33 @@ $activitysmith->liveActivities->stream( ); ``` +#### Timer + +
+
+
'float',
'value' => 'float',
'upperLimit' => 'float',
+ 'durationSeconds' => 'float',
+ 'countsDown' => 'bool',
+ 'isRunning' => 'bool',
'metrics' => '\ActivitySmith\Generated\Model\ActivityMetric[]',
'message' => 'string',
'icon' => '\ActivitySmith\Generated\Model\LiveActivityAlertIcon',
@@ -91,6 +94,9 @@ class ContentStateEnd implements ModelInterface, ArrayAccess, \JsonSerializable
'percentage' => null,
'value' => null,
'upperLimit' => null,
+ 'durationSeconds' => null,
+ 'countsDown' => null,
+ 'isRunning' => null,
'metrics' => null,
'message' => null,
'icon' => null,
@@ -115,6 +121,9 @@ class ContentStateEnd implements ModelInterface, ArrayAccess, \JsonSerializable
'percentage' => false,
'value' => false,
'upperLimit' => false,
+ 'durationSeconds' => false,
+ 'countsDown' => false,
+ 'isRunning' => false,
'metrics' => false,
'message' => false,
'icon' => false,
@@ -219,6 +228,9 @@ public function isNullableSetToNull(string $property): bool
'percentage' => 'percentage',
'value' => 'value',
'upperLimit' => 'upper_limit',
+ 'durationSeconds' => 'duration_seconds',
+ 'countsDown' => 'counts_down',
+ 'isRunning' => 'is_running',
'metrics' => 'metrics',
'message' => 'message',
'icon' => 'icon',
@@ -243,6 +255,9 @@ public function isNullableSetToNull(string $property): bool
'percentage' => 'setPercentage',
'value' => 'setValue',
'upperLimit' => 'setUpperLimit',
+ 'durationSeconds' => 'setDurationSeconds',
+ 'countsDown' => 'setCountsDown',
+ 'isRunning' => 'setIsRunning',
'metrics' => 'setMetrics',
'message' => 'setMessage',
'icon' => 'setIcon',
@@ -267,6 +282,9 @@ public function isNullableSetToNull(string $property): bool
'percentage' => 'getPercentage',
'value' => 'getValue',
'upperLimit' => 'getUpperLimit',
+ 'durationSeconds' => 'getDurationSeconds',
+ 'countsDown' => 'getCountsDown',
+ 'isRunning' => 'getIsRunning',
'metrics' => 'getMetrics',
'message' => 'getMessage',
'icon' => 'getIcon',
@@ -324,6 +342,7 @@ public function getModelName()
public const TYPE_METRICS = 'metrics';
public const TYPE_STATS = 'stats';
public const TYPE_ALERT = 'alert';
+ public const TYPE_TIMER = 'timer';
public const COLOR_LIME = 'lime';
public const COLOR_GREEN = 'green';
public const COLOR_CYAN = 'cyan';
@@ -368,6 +387,7 @@ public function getTypeAllowableValues()
self::TYPE_METRICS,
self::TYPE_STATS,
self::TYPE_ALERT,
+ self::TYPE_TIMER,
];
}
@@ -456,6 +476,9 @@ public function __construct(array $data = null)
$this->setIfExists('percentage', $data ?? [], null);
$this->setIfExists('value', $data ?? [], null);
$this->setIfExists('upperLimit', $data ?? [], null);
+ $this->setIfExists('durationSeconds', $data ?? [], null);
+ $this->setIfExists('countsDown', $data ?? [], true);
+ $this->setIfExists('isRunning', $data ?? [], true);
$this->setIfExists('metrics', $data ?? [], null);
$this->setIfExists('message', $data ?? [], null);
$this->setIfExists('icon', $data ?? [], null);
@@ -778,6 +801,87 @@ public function setUpperLimit($upperLimit)
return $this;
}
+ /**
+ * Gets durationSeconds
+ *
+ * @return float|null
+ */
+ public function getDurationSeconds()
+ {
+ return $this->container['durationSeconds'];
+ }
+
+ /**
+ * Sets durationSeconds
+ *
+ * @param float|null $durationSeconds Timer duration in seconds. For type=timer, omit duration_seconds on end to preserve and freeze the latest timer state.
+ *
+ * @return self
+ */
+ public function setDurationSeconds($durationSeconds)
+ {
+ if (is_null($durationSeconds)) {
+ throw new \InvalidArgumentException('non-nullable durationSeconds cannot be null');
+ }
+ $this->container['durationSeconds'] = $durationSeconds;
+
+ return $this;
+ }
+
+ /**
+ * Gets countsDown
+ *
+ * @return bool|null
+ */
+ public function getCountsDown()
+ {
+ return $this->container['countsDown'];
+ }
+
+ /**
+ * Sets countsDown
+ *
+ * @param bool|null $countsDown Use with type=timer. When true or omitted, the timer counts down from duration_seconds. Set false for an elapsed timer; omit duration_seconds for an open-ended elapsed timer.
+ *
+ * @return self
+ */
+ public function setCountsDown($countsDown)
+ {
+ if (is_null($countsDown)) {
+ throw new \InvalidArgumentException('non-nullable countsDown cannot be null');
+ }
+ $this->container['countsDown'] = $countsDown;
+
+ return $this;
+ }
+
+ /**
+ * Gets isRunning
+ *
+ * @return bool|null
+ */
+ public function getIsRunning()
+ {
+ return $this->container['isRunning'];
+ }
+
+ /**
+ * Sets isRunning
+ *
+ * @param bool|null $isRunning Use with type=timer. Defaults to true. Set false to pause/freeze via API; set true on a paused timer to resume.
+ *
+ * @return self
+ */
+ public function setIsRunning($isRunning)
+ {
+ if (is_null($isRunning)) {
+ throw new \InvalidArgumentException('non-nullable isRunning cannot be null');
+ }
+ $this->container['isRunning'] = $isRunning;
+
+ return $this;
+ }
+
/**
* Gets metrics
*
@@ -857,7 +961,7 @@ public function getIcon()
/**
* Sets icon
*
- * @param \ActivitySmith\Generated\Model\LiveActivityAlertIcon|null $icon Optional SF Symbol icon. Supported by alert, progress, segmented_progress, metrics, and stats.
+ * @param \ActivitySmith\Generated\Model\LiveActivityAlertIcon|null $icon Optional SF Symbol icon. Supported by alert, progress, segmented_progress, metrics, stats, and timer.
*
* @return self
*/
@@ -948,7 +1052,7 @@ public function getColor()
/**
* Sets color
*
- * @param string|null $color Optional. Accent color for progress, segmented_progress, and metrics Live Activities. For Alert Live Activities, this tints the action button when action is included.
+ * @param string|null $color Optional. Accent color for progress, segmented_progress, metrics, and timer Live Activities. For Alert Live Activities, this tints the action button when action is included.
*
* @return self
*/
diff --git a/generated/Model/ContentStateStart.php b/generated/Model/ContentStateStart.php
index 1a6f499..53305a9 100644
--- a/generated/Model/ContentStateStart.php
+++ b/generated/Model/ContentStateStart.php
@@ -35,7 +35,7 @@
* ContentStateStart Class Doc Comment
*
* @category Class
- * @description Start payload requires title and type. For segmented_progress include number_of_steps and current_step. For progress include percentage or value with upper_limit. For metrics and stats include a non-empty metrics array. For alert include message. Optional icon is supported by all Live Activity types. Optional badge is supported by alert, progress, and segmented_progress. For segmented_progress, number_of_steps is not locked and can be changed in later update or end calls.
+ * @description Start payload requires title and type. For segmented_progress include number_of_steps and current_step. For progress include percentage or value with upper_limit. For metrics and stats include a non-empty metrics array. For alert include message. For timer include duration_seconds for countdowns, or set counts_down false without duration_seconds for an open-ended elapsed timer. Optional icon is supported by all Live Activity types. Optional badge is supported by alert, progress, and segmented_progress. For segmented_progress, number_of_steps is not locked and can be changed in later update or end calls.
* @package ActivitySmith\Generated
* @author OpenAPI Generator team
* @link https://openapi-generator.tech
@@ -65,6 +65,9 @@ class ContentStateStart implements ModelInterface, ArrayAccess, \JsonSerializabl
'percentage' => 'float',
'value' => 'float',
'upperLimit' => 'float',
+ 'durationSeconds' => 'float',
+ 'countsDown' => 'bool',
+ 'isRunning' => 'bool',
'metrics' => '\ActivitySmith\Generated\Model\ActivityMetric[]',
'message' => 'string',
'icon' => '\ActivitySmith\Generated\Model\LiveActivityAlertIcon',
@@ -90,6 +93,9 @@ class ContentStateStart implements ModelInterface, ArrayAccess, \JsonSerializabl
'percentage' => null,
'value' => null,
'upperLimit' => null,
+ 'durationSeconds' => null,
+ 'countsDown' => null,
+ 'isRunning' => null,
'metrics' => null,
'message' => null,
'icon' => null,
@@ -113,6 +119,9 @@ class ContentStateStart implements ModelInterface, ArrayAccess, \JsonSerializabl
'percentage' => false,
'value' => false,
'upperLimit' => false,
+ 'durationSeconds' => false,
+ 'countsDown' => false,
+ 'isRunning' => false,
'metrics' => false,
'message' => false,
'icon' => false,
@@ -216,6 +225,9 @@ public function isNullableSetToNull(string $property): bool
'percentage' => 'percentage',
'value' => 'value',
'upperLimit' => 'upper_limit',
+ 'durationSeconds' => 'duration_seconds',
+ 'countsDown' => 'counts_down',
+ 'isRunning' => 'is_running',
'metrics' => 'metrics',
'message' => 'message',
'icon' => 'icon',
@@ -239,6 +251,9 @@ public function isNullableSetToNull(string $property): bool
'percentage' => 'setPercentage',
'value' => 'setValue',
'upperLimit' => 'setUpperLimit',
+ 'durationSeconds' => 'setDurationSeconds',
+ 'countsDown' => 'setCountsDown',
+ 'isRunning' => 'setIsRunning',
'metrics' => 'setMetrics',
'message' => 'setMessage',
'icon' => 'setIcon',
@@ -262,6 +277,9 @@ public function isNullableSetToNull(string $property): bool
'percentage' => 'getPercentage',
'value' => 'getValue',
'upperLimit' => 'getUpperLimit',
+ 'durationSeconds' => 'getDurationSeconds',
+ 'countsDown' => 'getCountsDown',
+ 'isRunning' => 'getIsRunning',
'metrics' => 'getMetrics',
'message' => 'getMessage',
'icon' => 'getIcon',
@@ -318,6 +336,7 @@ public function getModelName()
public const TYPE_METRICS = 'metrics';
public const TYPE_STATS = 'stats';
public const TYPE_ALERT = 'alert';
+ public const TYPE_TIMER = 'timer';
public const COLOR_LIME = 'lime';
public const COLOR_GREEN = 'green';
public const COLOR_CYAN = 'cyan';
@@ -362,6 +381,7 @@ public function getTypeAllowableValues()
self::TYPE_METRICS,
self::TYPE_STATS,
self::TYPE_ALERT,
+ self::TYPE_TIMER,
];
}
@@ -450,6 +470,9 @@ public function __construct(array $data = null)
$this->setIfExists('percentage', $data ?? [], null);
$this->setIfExists('value', $data ?? [], null);
$this->setIfExists('upperLimit', $data ?? [], null);
+ $this->setIfExists('durationSeconds', $data ?? [], null);
+ $this->setIfExists('countsDown', $data ?? [], true);
+ $this->setIfExists('isRunning', $data ?? [], true);
$this->setIfExists('metrics', $data ?? [], null);
$this->setIfExists('message', $data ?? [], null);
$this->setIfExists('icon', $data ?? [], null);
@@ -770,6 +793,87 @@ public function setUpperLimit($upperLimit)
return $this;
}
+ /**
+ * Gets durationSeconds
+ *
+ * @return float|null
+ */
+ public function getDurationSeconds()
+ {
+ return $this->container['durationSeconds'];
+ }
+
+ /**
+ * Sets durationSeconds
+ *
+ * @param float|null $durationSeconds Timer duration in seconds. For type=timer countdowns, required on start when counts_down is true or omitted.
+ *
+ * @return self
+ */
+ public function setDurationSeconds($durationSeconds)
+ {
+ if (is_null($durationSeconds)) {
+ throw new \InvalidArgumentException('non-nullable durationSeconds cannot be null');
+ }
+ $this->container['durationSeconds'] = $durationSeconds;
+
+ return $this;
+ }
+
+ /**
+ * Gets countsDown
+ *
+ * @return bool|null
+ */
+ public function getCountsDown()
+ {
+ return $this->container['countsDown'];
+ }
+
+ /**
+ * Sets countsDown
+ *
+ * @param bool|null $countsDown Use with type=timer. When true or omitted, the timer counts down from duration_seconds. Set false for an elapsed timer; omit duration_seconds for an open-ended elapsed timer.
+ *
+ * @return self
+ */
+ public function setCountsDown($countsDown)
+ {
+ if (is_null($countsDown)) {
+ throw new \InvalidArgumentException('non-nullable countsDown cannot be null');
+ }
+ $this->container['countsDown'] = $countsDown;
+
+ return $this;
+ }
+
+ /**
+ * Gets isRunning
+ *
+ * @return bool|null
+ */
+ public function getIsRunning()
+ {
+ return $this->container['isRunning'];
+ }
+
+ /**
+ * Sets isRunning
+ *
+ * @param bool|null $isRunning Use with type=timer. Defaults to true. Set false to pause/freeze via API; set true on a paused timer to resume.
+ *
+ * @return self
+ */
+ public function setIsRunning($isRunning)
+ {
+ if (is_null($isRunning)) {
+ throw new \InvalidArgumentException('non-nullable isRunning cannot be null');
+ }
+ $this->container['isRunning'] = $isRunning;
+
+ return $this;
+ }
+
/**
* Gets metrics
*
@@ -849,7 +953,7 @@ public function getIcon()
/**
* Sets icon
*
- * @param \ActivitySmith\Generated\Model\LiveActivityAlertIcon|null $icon Optional SF Symbol icon. Supported by alert, progress, segmented_progress, metrics, and stats.
+ * @param \ActivitySmith\Generated\Model\LiveActivityAlertIcon|null $icon Optional SF Symbol icon. Supported by alert, progress, segmented_progress, metrics, stats, and timer.
*
* @return self
*/
@@ -940,7 +1044,7 @@ public function getColor()
/**
* Sets color
*
- * @param string|null $color Optional. Accent color for progress, segmented_progress, and metrics Live Activities. For Alert Live Activities, this tints the action button when action is included.
+ * @param string|null $color Optional. Accent color for progress, segmented_progress, metrics, and timer Live Activities. For Alert Live Activities, this tints the action button when action is included.
*
* @return self
*/
diff --git a/generated/Model/ContentStateUpdate.php b/generated/Model/ContentStateUpdate.php
index 33cb40f..80c2c86 100644
--- a/generated/Model/ContentStateUpdate.php
+++ b/generated/Model/ContentStateUpdate.php
@@ -35,7 +35,7 @@
* ContentStateUpdate Class Doc Comment
*
* @category Class
- * @description Update payload requires title. For segmented_progress include current_step and optionally number_of_steps. For progress include percentage or value with upper_limit. For metrics and stats include a non-empty metrics array. For alert include message. Optional icon is supported by all Live Activity types. Optional badge is supported by alert, progress, and segmented_progress. Type is optional when updating an existing activity. You can increase or decrease number_of_steps during updates.
+ * @description Update payload requires title. For segmented_progress include current_step and optionally number_of_steps. For progress include percentage or value with upper_limit. For metrics and stats include a non-empty metrics array. For alert include message. For timer, omit duration_seconds to preserve the current timer window or send duration_seconds to reset the timer from the update request time. Optional icon is supported by all Live Activity types. Optional badge is supported by alert, progress, and segmented_progress. Type is optional when updating an existing activity. You can increase or decrease number_of_steps during updates.
* @package ActivitySmith\Generated
* @author OpenAPI Generator team
* @link https://openapi-generator.tech
@@ -65,6 +65,9 @@ class ContentStateUpdate implements ModelInterface, ArrayAccess, \JsonSerializab
'percentage' => 'float',
'value' => 'float',
'upperLimit' => 'float',
+ 'durationSeconds' => 'float',
+ 'countsDown' => 'bool',
+ 'isRunning' => 'bool',
'metrics' => '\ActivitySmith\Generated\Model\ActivityMetric[]',
'message' => 'string',
'icon' => '\ActivitySmith\Generated\Model\LiveActivityAlertIcon',
@@ -90,6 +93,9 @@ class ContentStateUpdate implements ModelInterface, ArrayAccess, \JsonSerializab
'percentage' => null,
'value' => null,
'upperLimit' => null,
+ 'durationSeconds' => null,
+ 'countsDown' => null,
+ 'isRunning' => null,
'metrics' => null,
'message' => null,
'icon' => null,
@@ -113,6 +119,9 @@ class ContentStateUpdate implements ModelInterface, ArrayAccess, \JsonSerializab
'percentage' => false,
'value' => false,
'upperLimit' => false,
+ 'durationSeconds' => false,
+ 'countsDown' => false,
+ 'isRunning' => false,
'metrics' => false,
'message' => false,
'icon' => false,
@@ -216,6 +225,9 @@ public function isNullableSetToNull(string $property): bool
'percentage' => 'percentage',
'value' => 'value',
'upperLimit' => 'upper_limit',
+ 'durationSeconds' => 'duration_seconds',
+ 'countsDown' => 'counts_down',
+ 'isRunning' => 'is_running',
'metrics' => 'metrics',
'message' => 'message',
'icon' => 'icon',
@@ -239,6 +251,9 @@ public function isNullableSetToNull(string $property): bool
'percentage' => 'setPercentage',
'value' => 'setValue',
'upperLimit' => 'setUpperLimit',
+ 'durationSeconds' => 'setDurationSeconds',
+ 'countsDown' => 'setCountsDown',
+ 'isRunning' => 'setIsRunning',
'metrics' => 'setMetrics',
'message' => 'setMessage',
'icon' => 'setIcon',
@@ -262,6 +277,9 @@ public function isNullableSetToNull(string $property): bool
'percentage' => 'getPercentage',
'value' => 'getValue',
'upperLimit' => 'getUpperLimit',
+ 'durationSeconds' => 'getDurationSeconds',
+ 'countsDown' => 'getCountsDown',
+ 'isRunning' => 'getIsRunning',
'metrics' => 'getMetrics',
'message' => 'getMessage',
'icon' => 'getIcon',
@@ -318,6 +336,7 @@ public function getModelName()
public const TYPE_METRICS = 'metrics';
public const TYPE_STATS = 'stats';
public const TYPE_ALERT = 'alert';
+ public const TYPE_TIMER = 'timer';
public const COLOR_LIME = 'lime';
public const COLOR_GREEN = 'green';
public const COLOR_CYAN = 'cyan';
@@ -362,6 +381,7 @@ public function getTypeAllowableValues()
self::TYPE_METRICS,
self::TYPE_STATS,
self::TYPE_ALERT,
+ self::TYPE_TIMER,
];
}
@@ -450,6 +470,9 @@ public function __construct(array $data = null)
$this->setIfExists('percentage', $data ?? [], null);
$this->setIfExists('value', $data ?? [], null);
$this->setIfExists('upperLimit', $data ?? [], null);
+ $this->setIfExists('durationSeconds', $data ?? [], null);
+ $this->setIfExists('countsDown', $data ?? [], true);
+ $this->setIfExists('isRunning', $data ?? [], true);
$this->setIfExists('metrics', $data ?? [], null);
$this->setIfExists('message', $data ?? [], null);
$this->setIfExists('icon', $data ?? [], null);
@@ -767,6 +790,87 @@ public function setUpperLimit($upperLimit)
return $this;
}
+ /**
+ * Gets durationSeconds
+ *
+ * @return float|null
+ */
+ public function getDurationSeconds()
+ {
+ return $this->container['durationSeconds'];
+ }
+
+ /**
+ * Sets durationSeconds
+ *
+ * @param float|null $durationSeconds Timer duration in seconds. For type=timer, sending duration_seconds resets the timer window from the update request time; omit it to preserve the existing timer window.
+ *
+ * @return self
+ */
+ public function setDurationSeconds($durationSeconds)
+ {
+ if (is_null($durationSeconds)) {
+ throw new \InvalidArgumentException('non-nullable durationSeconds cannot be null');
+ }
+ $this->container['durationSeconds'] = $durationSeconds;
+
+ return $this;
+ }
+
+ /**
+ * Gets countsDown
+ *
+ * @return bool|null
+ */
+ public function getCountsDown()
+ {
+ return $this->container['countsDown'];
+ }
+
+ /**
+ * Sets countsDown
+ *
+ * @param bool|null $countsDown Use with type=timer. When true or omitted, the timer counts down from duration_seconds. Set false for an elapsed timer; omit duration_seconds for an open-ended elapsed timer.
+ *
+ * @return self
+ */
+ public function setCountsDown($countsDown)
+ {
+ if (is_null($countsDown)) {
+ throw new \InvalidArgumentException('non-nullable countsDown cannot be null');
+ }
+ $this->container['countsDown'] = $countsDown;
+
+ return $this;
+ }
+
+ /**
+ * Gets isRunning
+ *
+ * @return bool|null
+ */
+ public function getIsRunning()
+ {
+ return $this->container['isRunning'];
+ }
+
+ /**
+ * Sets isRunning
+ *
+ * @param bool|null $isRunning Use with type=timer. Defaults to true. Set false to pause/freeze via API; set true on a paused timer to resume.
+ *
+ * @return self
+ */
+ public function setIsRunning($isRunning)
+ {
+ if (is_null($isRunning)) {
+ throw new \InvalidArgumentException('non-nullable isRunning cannot be null');
+ }
+ $this->container['isRunning'] = $isRunning;
+
+ return $this;
+ }
+
/**
* Gets metrics
*
@@ -846,7 +950,7 @@ public function getIcon()
/**
* Sets icon
*
- * @param \ActivitySmith\Generated\Model\LiveActivityAlertIcon|null $icon Optional SF Symbol icon. Supported by alert, progress, segmented_progress, metrics, and stats.
+ * @param \ActivitySmith\Generated\Model\LiveActivityAlertIcon|null $icon Optional SF Symbol icon. Supported by alert, progress, segmented_progress, metrics, stats, and timer.
*
* @return self
*/
@@ -937,7 +1041,7 @@ public function getColor()
/**
* Sets color
*
- * @param string|null $color Optional. Accent color for progress, segmented_progress, and metrics Live Activities. For Alert Live Activities, this tints the action button when action is included.
+ * @param string|null $color Optional. Accent color for progress, segmented_progress, metrics, and timer Live Activities. For Alert Live Activities, this tints the action button when action is included.
*
* @return self
*/
diff --git a/generated/Model/LiveActivityAction.php b/generated/Model/LiveActivityAction.php
index 6085812..d5e5220 100644
--- a/generated/Model/LiveActivityAction.php
+++ b/generated/Model/LiveActivityAction.php
@@ -312,15 +312,6 @@ public function listInvalidProperties()
if ($this->container['url'] === null) {
$invalidProperties[] = "'url' can't be null";
}
- if ($this->container['url'] !== null) {
- $actionType = $this->container['type'];
- if ($actionType === LiveActivityActionType::OPEN_URL && !preg_match('/^(https|shortcuts):\/\//', (string) $this->container['url'])) {
- $invalidProperties[] = "invalid value for 'url', open_url must use https or shortcuts.";
- }
- if ($actionType === LiveActivityActionType::WEBHOOK && !preg_match('/^https:\/\//', (string) $this->container['url'])) {
- $invalidProperties[] = "invalid value for 'url', webhook must use https.";
- }
- }
return $invalidProperties;
}
@@ -403,7 +394,7 @@ public function getUrl()
/**
* Sets url
*
- * @param string $url Action URL. For open_url, use an HTTPS URL or a shortcuts://run-shortcut?name=... URL. For webhook, use an HTTPS URL called by the ActivitySmith backend.
+ * @param string $url Action URL. For open_url, use an HTTPS URL or a shortcuts://run-shortcut?name=... URL that runs a specific iPhone Shortcut. For webhook, use an HTTPS URL called by the ActivitySmith backend.
*
* @return self
*/
@@ -412,13 +403,6 @@ public function setUrl($url)
if (is_null($url)) {
throw new \InvalidArgumentException('non-nullable url cannot be null');
}
- $actionType = $this->container['type'] ?? null;
- if ($actionType === LiveActivityActionType::OPEN_URL && !preg_match('/^(https|shortcuts):\/\//', (string) $url)) {
- throw new \InvalidArgumentException("invalid value for \$url when calling LiveActivityAction., open_url must use https or shortcuts.");
- }
- if ($actionType === LiveActivityActionType::WEBHOOK && !preg_match('/^https:\/\//', (string) $url)) {
- throw new \InvalidArgumentException("invalid value for \$url when calling LiveActivityAction., webhook must use https.");
- }
$this->container['url'] = $url;
return $this;
@@ -568,3 +552,4 @@ public function toHeaderValue()
}
}
+
diff --git a/generated/Model/PushNotificationAction.php b/generated/Model/PushNotificationAction.php
index 79c60fc..72d65a6 100644
--- a/generated/Model/PushNotificationAction.php
+++ b/generated/Model/PushNotificationAction.php
@@ -311,15 +311,6 @@ public function listInvalidProperties()
if ($this->container['url'] === null) {
$invalidProperties[] = "'url' can't be null";
}
- if ($this->container['url'] !== null) {
- $actionType = $this->container['type'];
- if ($actionType === PushNotificationActionType::OPEN_URL && !preg_match('/^(https|shortcuts):\/\//', (string) $this->container['url'])) {
- $invalidProperties[] = "invalid value for 'url', open_url must use https or shortcuts.";
- }
- if ($actionType === PushNotificationActionType::WEBHOOK && !preg_match('/^https:\/\//', (string) $this->container['url'])) {
- $invalidProperties[] = "invalid value for 'url', webhook must use https.";
- }
- }
return $invalidProperties;
}
@@ -402,7 +393,7 @@ public function getUrl()
/**
* Sets url
*
- * @param string $url Action URL. For open_url, use an HTTPS URL or a shortcuts://run-shortcut?name=... URL. For webhook, use an HTTPS URL called by the ActivitySmith backend.
+ * @param string $url Action URL. For open_url, use an HTTPS URL or a shortcuts://run-shortcut?name=... URL that runs a specific iPhone Shortcut. For webhook, use an HTTPS URL called by the ActivitySmith backend.
*
* @return self
*/
@@ -411,13 +402,6 @@ public function setUrl($url)
if (is_null($url)) {
throw new \InvalidArgumentException('non-nullable url cannot be null');
}
- $actionType = $this->container['type'] ?? null;
- if ($actionType === PushNotificationActionType::OPEN_URL && !preg_match('/^(https|shortcuts):\/\//', (string) $url)) {
- throw new \InvalidArgumentException("invalid value for \$url when calling PushNotificationAction., open_url must use https or shortcuts.");
- }
- if ($actionType === PushNotificationActionType::WEBHOOK && !preg_match('/^https:\/\//', (string) $url)) {
- throw new \InvalidArgumentException("invalid value for \$url when calling PushNotificationAction., webhook must use https.");
- }
$this->container['url'] = $url;
return $this;
@@ -567,3 +551,4 @@ public function toHeaderValue()
}
}
+
diff --git a/generated/Model/PushNotificationRequest.php b/generated/Model/PushNotificationRequest.php
index 99a3713..33bd6d9 100644
--- a/generated/Model/PushNotificationRequest.php
+++ b/generated/Model/PushNotificationRequest.php
@@ -493,7 +493,7 @@ public function getRedirection()
/**
* Sets redirection
*
- * @param string|null $redirection Optional HTTPS URL or shortcuts://run-shortcut?name=... URL opened when user taps the notification body. Overrides the default tap target from `media` when both are provided.
+ * @param string|null $redirection Optional HTTPS URL or shortcuts://run-shortcut?name=... URL opened when the user taps the notification body. Use shortcuts://run-shortcut?name=... to run a specific iPhone Shortcut that already exists on the user's device. Overrides the default tap target from `media` when both are provided.
*
* @return self
*/
diff --git a/generated/Model/StreamContentState.php b/generated/Model/StreamContentState.php
index c1e837f..762d0a5 100644
--- a/generated/Model/StreamContentState.php
+++ b/generated/Model/StreamContentState.php
@@ -35,7 +35,7 @@
* StreamContentState Class Doc Comment
*
* @category Class
- * @description Current state for a managed Live Activity stream. Include type on the first PUT, and whenever the stream may need to start a fresh activity. Supports segmented_progress, progress, metrics, stats, and alert types.
+ * @description Current state for a managed Live Activity stream. Include type on the first PUT, and whenever the stream may need to start a fresh activity. Supports segmented_progress, progress, metrics, stats, alert, and timer types. For timer, send duration_seconds to start or reset a bounded timer; omit duration_seconds on later updates to preserve the existing timer window.
* @package ActivitySmith\Generated
* @author OpenAPI Generator team
* @link https://openapi-generator.tech
@@ -65,6 +65,9 @@ class StreamContentState implements ModelInterface, ArrayAccess, \JsonSerializab
'percentage' => 'float',
'value' => 'float',
'upperLimit' => 'float',
+ 'durationSeconds' => 'float',
+ 'countsDown' => 'bool',
+ 'isRunning' => 'bool',
'type' => 'string',
'color' => 'string',
'stepColor' => 'string',
@@ -92,6 +95,9 @@ class StreamContentState implements ModelInterface, ArrayAccess, \JsonSerializab
'percentage' => null,
'value' => null,
'upperLimit' => null,
+ 'durationSeconds' => null,
+ 'countsDown' => null,
+ 'isRunning' => null,
'type' => null,
'color' => null,
'stepColor' => null,
@@ -117,6 +123,9 @@ class StreamContentState implements ModelInterface, ArrayAccess, \JsonSerializab
'percentage' => false,
'value' => false,
'upperLimit' => false,
+ 'durationSeconds' => false,
+ 'countsDown' => false,
+ 'isRunning' => false,
'type' => false,
'color' => false,
'stepColor' => false,
@@ -222,6 +231,9 @@ public function isNullableSetToNull(string $property): bool
'percentage' => 'percentage',
'value' => 'value',
'upperLimit' => 'upper_limit',
+ 'durationSeconds' => 'duration_seconds',
+ 'countsDown' => 'counts_down',
+ 'isRunning' => 'is_running',
'type' => 'type',
'color' => 'color',
'stepColor' => 'step_color',
@@ -247,6 +259,9 @@ public function isNullableSetToNull(string $property): bool
'percentage' => 'setPercentage',
'value' => 'setValue',
'upperLimit' => 'setUpperLimit',
+ 'durationSeconds' => 'setDurationSeconds',
+ 'countsDown' => 'setCountsDown',
+ 'isRunning' => 'setIsRunning',
'type' => 'setType',
'color' => 'setColor',
'stepColor' => 'setStepColor',
@@ -272,6 +287,9 @@ public function isNullableSetToNull(string $property): bool
'percentage' => 'getPercentage',
'value' => 'getValue',
'upperLimit' => 'getUpperLimit',
+ 'durationSeconds' => 'getDurationSeconds',
+ 'countsDown' => 'getCountsDown',
+ 'isRunning' => 'getIsRunning',
'type' => 'getType',
'color' => 'getColor',
'stepColor' => 'getStepColor',
@@ -330,6 +348,7 @@ public function getModelName()
public const TYPE_METRICS = 'metrics';
public const TYPE_STATS = 'stats';
public const TYPE_ALERT = 'alert';
+ public const TYPE_TIMER = 'timer';
public const COLOR_LIME = 'lime';
public const COLOR_GREEN = 'green';
public const COLOR_CYAN = 'cyan';
@@ -374,6 +393,7 @@ public function getTypeAllowableValues()
self::TYPE_METRICS,
self::TYPE_STATS,
self::TYPE_ALERT,
+ self::TYPE_TIMER,
];
}
@@ -462,6 +482,9 @@ public function __construct(array $data = null)
$this->setIfExists('percentage', $data ?? [], null);
$this->setIfExists('value', $data ?? [], null);
$this->setIfExists('upperLimit', $data ?? [], null);
+ $this->setIfExists('durationSeconds', $data ?? [], null);
+ $this->setIfExists('countsDown', $data ?? [], true);
+ $this->setIfExists('isRunning', $data ?? [], true);
$this->setIfExists('type', $data ?? [], null);
$this->setIfExists('color', $data ?? [], null);
$this->setIfExists('stepColor', $data ?? [], null);
@@ -789,6 +812,87 @@ public function setUpperLimit($upperLimit)
return $this;
}
+ /**
+ * Gets durationSeconds
+ *
+ * @return float|null
+ */
+ public function getDurationSeconds()
+ {
+ return $this->container['durationSeconds'];
+ }
+
+ /**
+ * Sets durationSeconds
+ *
+ * @param float|null $durationSeconds Timer duration in seconds. For type=timer, send duration_seconds to start or reset the timer window; omit it on later stream updates to preserve the existing timer window.
+ *
+ * @return self
+ */
+ public function setDurationSeconds($durationSeconds)
+ {
+ if (is_null($durationSeconds)) {
+ throw new \InvalidArgumentException('non-nullable durationSeconds cannot be null');
+ }
+ $this->container['durationSeconds'] = $durationSeconds;
+
+ return $this;
+ }
+
+ /**
+ * Gets countsDown
+ *
+ * @return bool|null
+ */
+ public function getCountsDown()
+ {
+ return $this->container['countsDown'];
+ }
+
+ /**
+ * Sets countsDown
+ *
+ * @param bool|null $countsDown Use with type=timer. When true or omitted, the timer counts down from duration_seconds. Set false for an elapsed timer; omit duration_seconds for an open-ended elapsed timer.
+ *
+ * @return self
+ */
+ public function setCountsDown($countsDown)
+ {
+ if (is_null($countsDown)) {
+ throw new \InvalidArgumentException('non-nullable countsDown cannot be null');
+ }
+ $this->container['countsDown'] = $countsDown;
+
+ return $this;
+ }
+
+ /**
+ * Gets isRunning
+ *
+ * @return bool|null
+ */
+ public function getIsRunning()
+ {
+ return $this->container['isRunning'];
+ }
+
+ /**
+ * Sets isRunning
+ *
+ * @param bool|null $isRunning Use with type=timer. Defaults to true. Set false to pause/freeze via API; set true on a paused timer to resume.
+ *
+ * @return self
+ */
+ public function setIsRunning($isRunning)
+ {
+ if (is_null($isRunning)) {
+ throw new \InvalidArgumentException('non-nullable isRunning cannot be null');
+ }
+ $this->container['isRunning'] = $isRunning;
+
+ return $this;
+ }
+
/**
* Gets type
*
@@ -839,7 +943,7 @@ public function getColor()
/**
* Sets color
*
- * @param string|null $color Optional. Accent color for progress, segmented_progress, and metrics Live Activities. For Alert Live Activities, this tints the action button when action is included.
+ * @param string|null $color Optional. Accent color for progress, segmented_progress, metrics, and timer Live Activities. For Alert Live Activities, this tints the action button when action is included.
*
* @return self
*/
@@ -1015,7 +1119,7 @@ public function getIcon()
/**
* Sets icon
*
- * @param \ActivitySmith\Generated\Model\LiveActivityAlertIcon|null $icon Optional SF Symbol icon. Supported by alert, progress, segmented_progress, metrics, and stats.
+ * @param \ActivitySmith\Generated\Model\LiveActivityAlertIcon|null $icon Optional SF Symbol icon. Supported by alert, progress, segmented_progress, metrics, stats, and timer.
*
* @return self
*/
diff --git a/src/LiveActivities.php b/src/LiveActivities.php
index b56f919..827b151 100644
--- a/src/LiveActivities.php
+++ b/src/LiveActivities.php
@@ -13,6 +13,7 @@ final class LiveActivities
public const TYPE_METRICS = 'metrics';
public const TYPE_STATS = 'stats';
public const TYPE_ALERT = 'alert';
+ public const TYPE_TIMER = 'timer';
public function __construct(private LiveActivitiesApi $api)
{
@@ -38,7 +39,9 @@ public function start(
mixed $action = null,
mixed $alert = null,
mixed $target = null,
- mixed $channels = null
+ mixed $channels = null,
+ mixed $durationSeconds = null,
+ mixed $countsDown = null
): mixed
{
$request = $this->buildRequest($request, $contentState, [
@@ -54,6 +57,8 @@ public function start(
'percentage' => $percentage,
'value' => $value,
'upper_limit' => $upperLimit,
+ 'duration_seconds' => $durationSeconds,
+ 'counts_down' => $countsDown,
'color' => $color,
'step_color' => $stepColor,
], [
@@ -84,7 +89,9 @@ public function update(
mixed $upperLimit = null,
mixed $color = null,
mixed $stepColor = null,
- mixed $action = null
+ mixed $action = null,
+ mixed $durationSeconds = null,
+ mixed $countsDown = null
): mixed
{
$request = $this->buildRequest($request, $contentState, [
@@ -100,6 +107,8 @@ public function update(
'percentage' => $percentage,
'value' => $value,
'upper_limit' => $upperLimit,
+ 'duration_seconds' => $durationSeconds,
+ 'counts_down' => $countsDown,
'color' => $color,
'step_color' => $stepColor,
], [
@@ -129,7 +138,9 @@ public function end(
mixed $color = null,
mixed $stepColor = null,
mixed $autoDismissMinutes = null,
- mixed $action = null
+ mixed $action = null,
+ mixed $durationSeconds = null,
+ mixed $countsDown = null
): mixed
{
$request = $this->buildRequest($request, $contentState, [
@@ -145,6 +156,8 @@ public function end(
'percentage' => $percentage,
'value' => $value,
'upper_limit' => $upperLimit,
+ 'duration_seconds' => $durationSeconds,
+ 'counts_down' => $countsDown,
'color' => $color,
'step_color' => $stepColor,
'auto_dismiss_minutes' => $autoDismissMinutes,
@@ -177,7 +190,9 @@ public function stream(
mixed $action = null,
mixed $alert = null,
mixed $target = null,
- mixed $channels = null
+ mixed $channels = null,
+ mixed $durationSeconds = null,
+ mixed $countsDown = null
): mixed
{
$request = $this->buildRequest($request, $contentState, [
@@ -193,6 +208,8 @@ public function stream(
'percentage' => $percentage,
'value' => $value,
'upper_limit' => $upperLimit,
+ 'duration_seconds' => $durationSeconds,
+ 'counts_down' => $countsDown,
'color' => $color,
'step_color' => $stepColor,
], [
@@ -228,7 +245,9 @@ public function endStream(
mixed $stepColor = null,
mixed $autoDismissMinutes = null,
mixed $action = null,
- mixed $alert = null
+ mixed $alert = null,
+ mixed $durationSeconds = null,
+ mixed $countsDown = null
): mixed
{
$request = $this->buildRequest($request, $contentState, [
@@ -244,6 +263,8 @@ public function endStream(
'percentage' => $percentage,
'value' => $value,
'upper_limit' => $upperLimit,
+ 'duration_seconds' => $durationSeconds,
+ 'counts_down' => $countsDown,
'color' => $color,
'step_color' => $stepColor,
'auto_dismiss_minutes' => $autoDismissMinutes,
diff --git a/src/LiveActivityContentState.php b/src/LiveActivityContentState.php
index 1deafcf..60fae9d 100644
--- a/src/LiveActivityContentState.php
+++ b/src/LiveActivityContentState.php
@@ -26,7 +26,9 @@ public static function make(
?string $color = null,
?string $stepColor = null,
?int $autoDismissSeconds = null,
- ?int $autoDismissMinutes = null
+ ?int $autoDismissMinutes = null,
+ int|float|null $durationSeconds = null,
+ ?bool $countsDown = null
): array {
$state = [
'title' => $title,
@@ -41,6 +43,8 @@ public static function make(
'percentage' => $percentage,
'value' => $value,
'upper_limit' => $upperLimit,
+ 'duration_seconds' => $durationSeconds,
+ 'counts_down' => $countsDown,
'color' => $color,
'step_color' => $stepColor,
'auto_dismiss_seconds' => $autoDismissSeconds,
diff --git a/src/Version.php b/src/Version.php
index b9dd0e3..a2453b9 100644
--- a/src/Version.php
+++ b/src/Version.php
@@ -6,7 +6,7 @@
final class Version
{
- public const VERSION = '1.5.0';
+ public const VERSION = '1.7.0';
private function __construct()
{
diff --git a/tests/ResourcesTest.php b/tests/ResourcesTest.php
index 0967f47..0fa9940 100644
--- a/tests/ResourcesTest.php
+++ b/tests/ResourcesTest.php
@@ -161,17 +161,6 @@ public function testGeneratedPushNotificationOpenUrlAllowsShortcuts(): void
$this->assertTrue($action->valid());
}
- public function testGeneratedPushNotificationWebhookRejectsShortcuts(): void
- {
- $action = new GeneratedPushNotificationAction([
- 'title' => 'Chat',
- 'type' => PushNotificationActionType::WEBHOOK,
- 'url' => 'shortcuts://run-shortcut?name=JARVIS',
- ]);
-
- $this->assertFalse($action->valid());
- }
-
public function testGeneratedPushNotificationRedirectionAllowsShortcuts(): void
{
$request = new GeneratedPushNotificationRequest([
@@ -193,17 +182,6 @@ public function testGeneratedLiveActivityOpenUrlAllowsShortcuts(): void
$this->assertTrue($action->valid());
}
- public function testGeneratedLiveActivityWebhookRejectsShortcuts(): void
- {
- $action = new GeneratedLiveActivityAction([
- 'title' => 'Chat',
- 'type' => LiveActivityActionType::WEBHOOK,
- 'url' => 'shortcuts://run-shortcut?name=JARVIS',
- ]);
-
- $this->assertFalse($action->valid());
- }
-
public function testNotificationsMapsChannelsToTarget(): void
{
$captured = [];
@@ -565,6 +543,92 @@ public function testLiveActivitiesSupportProgressPayloads(): void
);
}
+ public function testLiveActivitiesSupportTimerPayloads(): void
+ {
+ $captured = [
+ 'start' => [],
+ 'update' => [],
+ ];
+ $response = (object) ['success' => true];
+
+ $api = $this->getMockBuilder(LiveActivitiesApi::class)
+ ->disableOriginalConstructor()
+ ->onlyMethods(['startLiveActivity', 'updateLiveActivity'])
+ ->getMock();
+
+ $api->expects($this->once())
+ ->method('startLiveActivity')
+ ->willReturnCallback(function (...$args) use (&$captured, $response) {
+ $captured['start'][] = $args;
+ return $response;
+ });
+
+ $api->expects($this->once())
+ ->method('updateLiveActivity')
+ ->willReturnCallback(function (...$args) use (&$captured, $response) {
+ $captured['update'][] = $args;
+ return $response;
+ });
+
+ $resource = new LiveActivities($api);
+ $state = LiveActivityContentState::make(
+ title: 'Benchmark Run',
+ subtitle: 'sampling performance',
+ type: LiveActivities::TYPE_TIMER,
+ durationSeconds: 300,
+ countsDown: true,
+ color: 'cyan'
+ );
+
+ $this->assertSame($response, $resource->start(contentState: $state));
+ $this->assertSame(
+ $response,
+ $resource->update(
+ activityId: 'act-1',
+ title: 'Benchmark Run',
+ type: LiveActivities::TYPE_TIMER,
+ subtitle: 'complete',
+ color: 'cyan'
+ )
+ );
+
+ $this->assertSame(
+ [
+ [
+ [
+ 'content_state' => [
+ 'title' => 'Benchmark Run',
+ 'subtitle' => 'sampling performance',
+ 'type' => LiveActivities::TYPE_TIMER,
+ 'duration_seconds' => 300,
+ 'counts_down' => true,
+ 'color' => 'cyan',
+ ],
+ ],
+ LiveActivitiesApi::contentTypes['startLiveActivity'][0],
+ ],
+ ],
+ $captured['start']
+ );
+ $this->assertSame(
+ [
+ [
+ [
+ 'activity_id' => 'act-1',
+ 'content_state' => [
+ 'title' => 'Benchmark Run',
+ 'subtitle' => 'complete',
+ 'type' => LiveActivities::TYPE_TIMER,
+ 'color' => 'cyan',
+ ],
+ ],
+ LiveActivitiesApi::contentTypes['updateLiveActivity'][0],
+ ],
+ ],
+ $captured['update']
+ );
+ }
+
public function testLiveActivitiesSupportStatsPayloads(): void
{
$captured = [];
diff --git a/tests/SmokeTest.php b/tests/SmokeTest.php
index 5a2f77c..52cd535 100644
--- a/tests/SmokeTest.php
+++ b/tests/SmokeTest.php
@@ -28,6 +28,6 @@ public function testClientConstructsWhenGeneratedCodeIsPresent(): void
$this->assertTrue(method_exists($client->liveActivities, 'endStream'));
$this->assertNotNull($client->metrics);
$this->assertTrue(method_exists($client->metrics, 'update'));
- $this->assertSame('1.5.0', Version::VERSION);
+ $this->assertSame('1.7.0', Version::VERSION);
}
}