diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..9485214
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,5 @@
+## 1.9.0
+
+### New Features
+
+- **New Feature: App Icon Badge Count** - Show MRR, user counts, stock prices, and more on your ActivitySmith app icon.
diff --git a/README.md b/README.md
index 7ca7ae7..ad2cf0e 100644
--- a/README.md
+++ b/README.md
@@ -20,8 +20,9 @@ See [API reference](https://activitysmith.com/docs/api-reference/introduction).
- [Live Activity Action](#live-activity-action)
- [Icons and Badges](#icons-and-badges)
- [Live Activity Colors](#live-activity-colors)
-- [Channels](#channels)
- [Widgets](#widgets)
+- [App Icon Badge Count](#app-icon-badge-count)
+- [Channels](#channels)
## Installation
@@ -535,20 +536,6 @@ Choose from these colors for the Live Activity accent, including progress bars a
`lime`, `green`, `cyan`, `blue`, `purple`, `magenta`, `red`, `orange`, `yellow`, `gray`
-## Channels
-
-Channels are used to target specific team members or devices. Can be used for both push notifications and live activities.
-
-```ruby
-activitysmith.notifications.send(
- {
- title: "New subscription 💸",
- message: "Customer upgraded to Pro plan",
- channels: ["sales", "customer-success"] # Optional
- }
-)
-```
-
## Widgets
@@ -571,6 +558,64 @@ String metric values work too.
activitysmith.metrics.update("prod.status", "healthy")
```
+## App Icon Badge Count
+
+
+
+
+
+Show the number you care about on your ActivitySmith app icon. Track MRR, a customer count, a stock price, or any other value you want to keep in view.
+
+Set or update the badge value.
+
+```ruby
+activitysmith.badge_count(8333)
+```
+
+To clear the badge, set its value to 0.
+
+```ruby
+activitysmith.badge_count(0)
+```
+
+## Channels
+
+Use `channels` to target specific team members or devices
+
+### Push Notifications
+
+```ruby
+activitysmith.notifications.send(
+ {
+ title: "New subscription 💸",
+ message: "Customer upgraded to Pro plan",
+ channels: ["sales", "customer-success"]
+ }
+)
+```
+
+### Live Activities
+
+```ruby
+activitysmith.live_activities.start(
+ {
+ content_state: {
+ title: "Nightly Database Backup",
+ subtitle: "verify restore",
+ type: "progress",
+ percentage: 62
+ },
+ channels: ["sales", "customer-success"]
+ }
+)
+```
+
+### App Icon Badge Count
+
+```ruby
+activitysmith.badge_count(3, channels: ["sales", "customer-success"])
+```
+
## Error Handling
```ruby
diff --git a/generated/activitysmith_openapi.rb b/generated/activitysmith_openapi.rb
index 7d5aee2..9928336 100644
--- a/generated/activitysmith_openapi.rb
+++ b/generated/activitysmith_openapi.rb
@@ -20,6 +20,8 @@
require 'activitysmith_openapi/models/activity_metric'
require 'activitysmith_openapi/models/activity_metric_value'
require 'activitysmith_openapi/models/alert_payload'
+require 'activitysmith_openapi/models/app_icon_badge_count_update_request'
+require 'activitysmith_openapi/models/app_icon_badge_count_update_response'
require 'activitysmith_openapi/models/bad_request_error'
require 'activitysmith_openapi/models/channel_target'
require 'activitysmith_openapi/models/content_state_end'
@@ -59,6 +61,7 @@
require 'activitysmith_openapi/models/stream_content_state'
# APIs
+require 'activitysmith_openapi/api/app_icon_badges_api'
require 'activitysmith_openapi/api/live_activities_api'
require 'activitysmith_openapi/api/metrics_api'
require 'activitysmith_openapi/api/push_notifications_api'
diff --git a/generated/activitysmith_openapi/api/app_icon_badges_api.rb b/generated/activitysmith_openapi/api/app_icon_badges_api.rb
new file mode 100644
index 0000000..0ee813e
--- /dev/null
+++ b/generated/activitysmith_openapi/api/app_icon_badges_api.rb
@@ -0,0 +1,90 @@
+=begin
+#ActivitySmith API
+
+#Send push notifications and Live Activities to your own devices via a single API key.
+
+The version of the OpenAPI document: 1.0.0
+
+Generated by: https://openapi-generator.tech
+Generator version: 7.7.0
+
+=end
+
+require 'cgi'
+
+module OpenapiClient
+ class AppIconBadgesApi
+ attr_accessor :api_client
+
+ def initialize(api_client = ApiClient.default)
+ @api_client = api_client
+ end
+ # Update App Icon Badge Count
+ # Updates the App Icon Badge Count on devices matched by API key scope and optional target channels. Send `badge: 0` to clear the count. Badge updates are independent of push notifications and do not create a push notification history item.
+ # @param app_icon_badge_count_update_request [AppIconBadgeCountUpdateRequest]
+ # @param [Hash] opts the optional parameters
+ # @return [AppIconBadgeCountUpdateResponse]
+ def update_app_icon_badge_count(app_icon_badge_count_update_request, opts = {})
+ data, _status_code, _headers = update_app_icon_badge_count_with_http_info(app_icon_badge_count_update_request, opts)
+ data
+ end
+
+ # Update App Icon Badge Count
+ # Updates the App Icon Badge Count on devices matched by API key scope and optional target channels. Send `badge: 0` to clear the count. Badge updates are independent of push notifications and do not create a push notification history item.
+ # @param app_icon_badge_count_update_request [AppIconBadgeCountUpdateRequest]
+ # @param [Hash] opts the optional parameters
+ # @return [Array<(AppIconBadgeCountUpdateResponse, Integer, Hash)>] AppIconBadgeCountUpdateResponse data, response status code and response headers
+ def update_app_icon_badge_count_with_http_info(app_icon_badge_count_update_request, opts = {})
+ if @api_client.config.debugging
+ @api_client.config.logger.debug 'Calling API: AppIconBadgesApi.update_app_icon_badge_count ...'
+ end
+ # verify the required parameter 'app_icon_badge_count_update_request' is set
+ if @api_client.config.client_side_validation && app_icon_badge_count_update_request.nil?
+ fail ArgumentError, "Missing the required parameter 'app_icon_badge_count_update_request' when calling AppIconBadgesApi.update_app_icon_badge_count"
+ end
+ # resource path
+ local_var_path = '/badge'
+
+ # query parameters
+ query_params = opts[:query_params] || {}
+
+ # header parameters
+ header_params = opts[:header_params] || {}
+ # HTTP header 'Accept' (if needed)
+ header_params['Accept'] = @api_client.select_header_accept(['application/json'])
+ # HTTP header 'Content-Type'
+ content_type = @api_client.select_header_content_type(['application/json'])
+ if !content_type.nil?
+ header_params['Content-Type'] = content_type
+ end
+
+ # form parameters
+ form_params = opts[:form_params] || {}
+
+ # http body (model)
+ post_body = opts[:debug_body] || @api_client.object_to_http_body(app_icon_badge_count_update_request)
+
+ # return_type
+ return_type = opts[:debug_return_type] || 'AppIconBadgeCountUpdateResponse'
+
+ # auth_names
+ auth_names = opts[:debug_auth_names] || ['apiKeyAuth']
+
+ new_options = opts.merge(
+ :operation => :"AppIconBadgesApi.update_app_icon_badge_count",
+ :header_params => header_params,
+ :query_params => query_params,
+ :form_params => form_params,
+ :body => post_body,
+ :auth_names => auth_names,
+ :return_type => return_type
+ )
+
+ data, status_code, headers = @api_client.call_api(:POST, local_var_path, new_options)
+ if @api_client.config.debugging
+ @api_client.config.logger.debug "API called: AppIconBadgesApi#update_app_icon_badge_count\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}"
+ end
+ return data, status_code, headers
+ end
+ end
+end
diff --git a/generated/activitysmith_openapi/models/app_icon_badge_count_update_request.rb b/generated/activitysmith_openapi/models/app_icon_badge_count_update_request.rb
new file mode 100644
index 0000000..090f14d
--- /dev/null
+++ b/generated/activitysmith_openapi/models/app_icon_badge_count_update_request.rb
@@ -0,0 +1,260 @@
+=begin
+#ActivitySmith API
+
+#Send push notifications and Live Activities to your own devices via a single API key.
+
+The version of the OpenAPI document: 1.0.0
+
+Generated by: https://openapi-generator.tech
+Generator version: 7.7.0
+
+=end
+
+require 'date'
+require 'time'
+
+module OpenapiClient
+ # App Icon Badge Count update. Send badge 0 to clear the count.
+ class AppIconBadgeCountUpdateRequest
+ # The count to show on the ActivitySmith app icon. Send 0 to clear it.
+ attr_accessor :badge
+
+ attr_accessor :target
+
+ # Attribute mapping from ruby-style variable name to JSON key.
+ def self.attribute_map
+ {
+ :'badge' => :'badge',
+ :'target' => :'target'
+ }
+ end
+
+ # Returns all the JSON keys this model knows about
+ def self.acceptable_attributes
+ attribute_map.values
+ end
+
+ # Attribute type mapping.
+ def self.openapi_types
+ {
+ :'badge' => :'Integer',
+ :'target' => :'ChannelTarget'
+ }
+ end
+
+ # List of attributes with nullable: true
+ def self.openapi_nullable
+ Set.new([
+ ])
+ end
+
+ # Initializes the object
+ # @param [Hash] attributes Model attributes in the form of hash
+ def initialize(attributes = {})
+ if (!attributes.is_a?(Hash))
+ fail ArgumentError, "The input argument (attributes) must be a hash in `OpenapiClient::AppIconBadgeCountUpdateRequest` initialize method"
+ end
+
+ # check to see if the attribute exists and convert string to symbol for hash key
+ attributes = attributes.each_with_object({}) { |(k, v), h|
+ if (!self.class.attribute_map.key?(k.to_sym))
+ fail ArgumentError, "`#{k}` is not a valid attribute in `OpenapiClient::AppIconBadgeCountUpdateRequest`. Please check the name to make sure it's valid. List of attributes: " + self.class.attribute_map.keys.inspect
+ end
+ h[k.to_sym] = v
+ }
+
+ if attributes.key?(:'badge')
+ self.badge = attributes[:'badge']
+ else
+ self.badge = nil
+ end
+
+ if attributes.key?(:'target')
+ self.target = attributes[:'target']
+ end
+ end
+
+ # Show invalid properties with the reasons. Usually used together with valid?
+ # @return Array for valid properties with the reasons
+ def list_invalid_properties
+ warn '[DEPRECATED] the `list_invalid_properties` method is obsolete'
+ invalid_properties = Array.new
+ if @badge.nil?
+ invalid_properties.push('invalid value for "badge", badge cannot be nil.')
+ end
+
+ if @badge > 2147483647
+ invalid_properties.push('invalid value for "badge", must be smaller than or equal to 2147483647.')
+ end
+
+ if @badge < 0
+ invalid_properties.push('invalid value for "badge", must be greater than or equal to 0.')
+ end
+
+ invalid_properties
+ end
+
+ # Check to see if the all the properties in the model are valid
+ # @return true if the model is valid
+ def valid?
+ warn '[DEPRECATED] the `valid?` method is obsolete'
+ return false if @badge.nil?
+ return false if @badge > 2147483647
+ return false if @badge < 0
+ true
+ end
+
+ # Custom attribute writer method with validation
+ # @param [Object] badge Value to be assigned
+ def badge=(badge)
+ if badge.nil?
+ fail ArgumentError, 'badge cannot be nil'
+ end
+
+ if badge > 2147483647
+ fail ArgumentError, 'invalid value for "badge", must be smaller than or equal to 2147483647.'
+ end
+
+ if badge < 0
+ fail ArgumentError, 'invalid value for "badge", must be greater than or equal to 0.'
+ end
+
+ @badge = badge
+ end
+
+ # Checks equality by comparing each attribute.
+ # @param [Object] Object to be compared
+ def ==(o)
+ return true if self.equal?(o)
+ self.class == o.class &&
+ badge == o.badge &&
+ target == o.target
+ end
+
+ # @see the `==` method
+ # @param [Object] Object to be compared
+ def eql?(o)
+ self == o
+ end
+
+ # Calculates hash code according to all attributes.
+ # @return [Integer] Hash code
+ def hash
+ [badge, target].hash
+ end
+
+ # Builds the object from hash
+ # @param [Hash] attributes Model attributes in the form of hash
+ # @return [Object] Returns the model itself
+ def self.build_from_hash(attributes)
+ return nil unless attributes.is_a?(Hash)
+ attributes = attributes.transform_keys(&:to_sym)
+ transformed_hash = {}
+ openapi_types.each_pair do |key, type|
+ if attributes.key?(attribute_map[key]) && attributes[attribute_map[key]].nil?
+ transformed_hash["#{key}"] = nil
+ elsif type =~ /\AArray<(.*)>/i
+ # check to ensure the input is an array given that the attribute
+ # is documented as an array but the input is not
+ if attributes[attribute_map[key]].is_a?(Array)
+ transformed_hash["#{key}"] = attributes[attribute_map[key]].map { |v| _deserialize($1, v) }
+ end
+ elsif !attributes[attribute_map[key]].nil?
+ transformed_hash["#{key}"] = _deserialize(type, attributes[attribute_map[key]])
+ end
+ end
+ new(transformed_hash)
+ end
+
+ # Deserializes the data based on type
+ # @param string type Data type
+ # @param string value Value to be deserialized
+ # @return [Object] Deserialized data
+ def self._deserialize(type, value)
+ case type.to_sym
+ when :Time
+ Time.parse(value)
+ when :Date
+ Date.parse(value)
+ when :String
+ value.to_s
+ when :Integer
+ value.to_i
+ when :Float
+ value.to_f
+ when :Boolean
+ if value.to_s =~ /\A(true|t|yes|y|1)\z/i
+ true
+ else
+ false
+ end
+ when :Object
+ # generic object (usually a Hash), return directly
+ value
+ when /\AArray<(?.+)>\z/
+ inner_type = Regexp.last_match[:inner_type]
+ value.map { |v| _deserialize(inner_type, v) }
+ when /\AHash<(?.+?), (?.+)>\z/
+ k_type = Regexp.last_match[:k_type]
+ v_type = Regexp.last_match[:v_type]
+ {}.tap do |hash|
+ value.each do |k, v|
+ hash[_deserialize(k_type, k)] = _deserialize(v_type, v)
+ end
+ end
+ else # model
+ # models (e.g. Pet) or oneOf
+ klass = OpenapiClient.const_get(type)
+ klass.respond_to?(:openapi_any_of) || klass.respond_to?(:openapi_one_of) ? klass.build(value) : klass.build_from_hash(value)
+ end
+ end
+
+ # Returns the string representation of the object
+ # @return [String] String presentation of the object
+ def to_s
+ to_hash.to_s
+ end
+
+ # to_body is an alias to to_hash (backward compatibility)
+ # @return [Hash] Returns the object in the form of hash
+ def to_body
+ to_hash
+ end
+
+ # Returns the object in the form of hash
+ # @return [Hash] Returns the object in the form of hash
+ def to_hash
+ hash = {}
+ self.class.attribute_map.each_pair do |attr, param|
+ value = self.send(attr)
+ if value.nil?
+ is_nullable = self.class.openapi_nullable.include?(attr)
+ next if !is_nullable || (is_nullable && !instance_variable_defined?(:"@#{attr}"))
+ end
+
+ hash[param] = _to_hash(value)
+ end
+ hash
+ end
+
+ # Outputs non-array value in the form of hash
+ # For object, use to_hash. Otherwise, just return the value
+ # @param [Object] value Any valid value
+ # @return [Hash] Returns the value in the form of hash
+ def _to_hash(value)
+ if value.is_a?(Array)
+ value.compact.map { |v| _to_hash(v) }
+ elsif value.is_a?(Hash)
+ {}.tap do |hash|
+ value.each { |k, v| hash[k] = _to_hash(v) }
+ end
+ elsif value.respond_to? :to_hash
+ value.to_hash
+ else
+ value
+ end
+ end
+
+ end
+
+end
diff --git a/generated/activitysmith_openapi/models/app_icon_badge_count_update_response.rb b/generated/activitysmith_openapi/models/app_icon_badge_count_update_response.rb
new file mode 100644
index 0000000..9faa31c
--- /dev/null
+++ b/generated/activitysmith_openapi/models/app_icon_badge_count_update_response.rb
@@ -0,0 +1,331 @@
+=begin
+#ActivitySmith API
+
+#Send push notifications and Live Activities to your own devices via a single API key.
+
+The version of the OpenAPI document: 1.0.0
+
+Generated by: https://openapi-generator.tech
+Generator version: 7.7.0
+
+=end
+
+require 'date'
+require 'time'
+
+module OpenapiClient
+ class AppIconBadgeCountUpdateResponse
+ attr_accessor :success
+
+ attr_accessor :badge
+
+ attr_accessor :devices_notified
+
+ attr_accessor :users_notified
+
+ attr_accessor :effective_channel_slugs
+
+ attr_accessor :timestamp
+
+ # Attribute mapping from ruby-style variable name to JSON key.
+ def self.attribute_map
+ {
+ :'success' => :'success',
+ :'badge' => :'badge',
+ :'devices_notified' => :'devices_notified',
+ :'users_notified' => :'users_notified',
+ :'effective_channel_slugs' => :'effective_channel_slugs',
+ :'timestamp' => :'timestamp'
+ }
+ end
+
+ # Returns all the JSON keys this model knows about
+ def self.acceptable_attributes
+ attribute_map.values
+ end
+
+ # Attribute type mapping.
+ def self.openapi_types
+ {
+ :'success' => :'Boolean',
+ :'badge' => :'Integer',
+ :'devices_notified' => :'Integer',
+ :'users_notified' => :'Integer',
+ :'effective_channel_slugs' => :'Array',
+ :'timestamp' => :'Time'
+ }
+ end
+
+ # List of attributes with nullable: true
+ def self.openapi_nullable
+ Set.new([
+ ])
+ end
+
+ # Initializes the object
+ # @param [Hash] attributes Model attributes in the form of hash
+ def initialize(attributes = {})
+ if (!attributes.is_a?(Hash))
+ fail ArgumentError, "The input argument (attributes) must be a hash in `OpenapiClient::AppIconBadgeCountUpdateResponse` initialize method"
+ end
+
+ # check to see if the attribute exists and convert string to symbol for hash key
+ attributes = attributes.each_with_object({}) { |(k, v), h|
+ if (!self.class.attribute_map.key?(k.to_sym))
+ fail ArgumentError, "`#{k}` is not a valid attribute in `OpenapiClient::AppIconBadgeCountUpdateResponse`. Please check the name to make sure it's valid. List of attributes: " + self.class.attribute_map.keys.inspect
+ end
+ h[k.to_sym] = v
+ }
+
+ if attributes.key?(:'success')
+ self.success = attributes[:'success']
+ else
+ self.success = nil
+ end
+
+ if attributes.key?(:'badge')
+ self.badge = attributes[:'badge']
+ else
+ self.badge = nil
+ end
+
+ if attributes.key?(:'devices_notified')
+ self.devices_notified = attributes[:'devices_notified']
+ else
+ self.devices_notified = nil
+ end
+
+ if attributes.key?(:'users_notified')
+ self.users_notified = attributes[:'users_notified']
+ else
+ self.users_notified = nil
+ end
+
+ if attributes.key?(:'effective_channel_slugs')
+ if (value = attributes[:'effective_channel_slugs']).is_a?(Array)
+ self.effective_channel_slugs = value
+ end
+ else
+ self.effective_channel_slugs = nil
+ end
+
+ if attributes.key?(:'timestamp')
+ self.timestamp = attributes[:'timestamp']
+ else
+ self.timestamp = nil
+ end
+ end
+
+ # Show invalid properties with the reasons. Usually used together with valid?
+ # @return Array for valid properties with the reasons
+ def list_invalid_properties
+ warn '[DEPRECATED] the `list_invalid_properties` method is obsolete'
+ invalid_properties = Array.new
+ if @success.nil?
+ invalid_properties.push('invalid value for "success", success cannot be nil.')
+ end
+
+ if @badge.nil?
+ invalid_properties.push('invalid value for "badge", badge cannot be nil.')
+ end
+
+ if @badge > 2147483647
+ invalid_properties.push('invalid value for "badge", must be smaller than or equal to 2147483647.')
+ end
+
+ if @badge < 0
+ invalid_properties.push('invalid value for "badge", must be greater than or equal to 0.')
+ end
+
+ if @devices_notified.nil?
+ invalid_properties.push('invalid value for "devices_notified", devices_notified cannot be nil.')
+ end
+
+ if @users_notified.nil?
+ invalid_properties.push('invalid value for "users_notified", users_notified cannot be nil.')
+ end
+
+ if @effective_channel_slugs.nil?
+ invalid_properties.push('invalid value for "effective_channel_slugs", effective_channel_slugs cannot be nil.')
+ end
+
+ if @timestamp.nil?
+ invalid_properties.push('invalid value for "timestamp", timestamp cannot be nil.')
+ end
+
+ invalid_properties
+ end
+
+ # Check to see if the all the properties in the model are valid
+ # @return true if the model is valid
+ def valid?
+ warn '[DEPRECATED] the `valid?` method is obsolete'
+ return false if @success.nil?
+ return false if @badge.nil?
+ return false if @badge > 2147483647
+ return false if @badge < 0
+ return false if @devices_notified.nil?
+ return false if @users_notified.nil?
+ return false if @effective_channel_slugs.nil?
+ return false if @timestamp.nil?
+ true
+ end
+
+ # Custom attribute writer method with validation
+ # @param [Object] badge Value to be assigned
+ def badge=(badge)
+ if badge.nil?
+ fail ArgumentError, 'badge cannot be nil'
+ end
+
+ if badge > 2147483647
+ fail ArgumentError, 'invalid value for "badge", must be smaller than or equal to 2147483647.'
+ end
+
+ if badge < 0
+ fail ArgumentError, 'invalid value for "badge", must be greater than or equal to 0.'
+ end
+
+ @badge = badge
+ end
+
+ # Checks equality by comparing each attribute.
+ # @param [Object] Object to be compared
+ def ==(o)
+ return true if self.equal?(o)
+ self.class == o.class &&
+ success == o.success &&
+ badge == o.badge &&
+ devices_notified == o.devices_notified &&
+ users_notified == o.users_notified &&
+ effective_channel_slugs == o.effective_channel_slugs &&
+ timestamp == o.timestamp
+ end
+
+ # @see the `==` method
+ # @param [Object] Object to be compared
+ def eql?(o)
+ self == o
+ end
+
+ # Calculates hash code according to all attributes.
+ # @return [Integer] Hash code
+ def hash
+ [success, badge, devices_notified, users_notified, effective_channel_slugs, timestamp].hash
+ end
+
+ # Builds the object from hash
+ # @param [Hash] attributes Model attributes in the form of hash
+ # @return [Object] Returns the model itself
+ def self.build_from_hash(attributes)
+ return nil unless attributes.is_a?(Hash)
+ attributes = attributes.transform_keys(&:to_sym)
+ transformed_hash = {}
+ openapi_types.each_pair do |key, type|
+ if attributes.key?(attribute_map[key]) && attributes[attribute_map[key]].nil?
+ transformed_hash["#{key}"] = nil
+ elsif type =~ /\AArray<(.*)>/i
+ # check to ensure the input is an array given that the attribute
+ # is documented as an array but the input is not
+ if attributes[attribute_map[key]].is_a?(Array)
+ transformed_hash["#{key}"] = attributes[attribute_map[key]].map { |v| _deserialize($1, v) }
+ end
+ elsif !attributes[attribute_map[key]].nil?
+ transformed_hash["#{key}"] = _deserialize(type, attributes[attribute_map[key]])
+ end
+ end
+ new(transformed_hash)
+ end
+
+ # Deserializes the data based on type
+ # @param string type Data type
+ # @param string value Value to be deserialized
+ # @return [Object] Deserialized data
+ def self._deserialize(type, value)
+ case type.to_sym
+ when :Time
+ Time.parse(value)
+ when :Date
+ Date.parse(value)
+ when :String
+ value.to_s
+ when :Integer
+ value.to_i
+ when :Float
+ value.to_f
+ when :Boolean
+ if value.to_s =~ /\A(true|t|yes|y|1)\z/i
+ true
+ else
+ false
+ end
+ when :Object
+ # generic object (usually a Hash), return directly
+ value
+ when /\AArray<(?.+)>\z/
+ inner_type = Regexp.last_match[:inner_type]
+ value.map { |v| _deserialize(inner_type, v) }
+ when /\AHash<(?.+?), (?.+)>\z/
+ k_type = Regexp.last_match[:k_type]
+ v_type = Regexp.last_match[:v_type]
+ {}.tap do |hash|
+ value.each do |k, v|
+ hash[_deserialize(k_type, k)] = _deserialize(v_type, v)
+ end
+ end
+ else # model
+ # models (e.g. Pet) or oneOf
+ klass = OpenapiClient.const_get(type)
+ klass.respond_to?(:openapi_any_of) || klass.respond_to?(:openapi_one_of) ? klass.build(value) : klass.build_from_hash(value)
+ end
+ end
+
+ # Returns the string representation of the object
+ # @return [String] String presentation of the object
+ def to_s
+ to_hash.to_s
+ end
+
+ # to_body is an alias to to_hash (backward compatibility)
+ # @return [Hash] Returns the object in the form of hash
+ def to_body
+ to_hash
+ end
+
+ # Returns the object in the form of hash
+ # @return [Hash] Returns the object in the form of hash
+ def to_hash
+ hash = {}
+ self.class.attribute_map.each_pair do |attr, param|
+ value = self.send(attr)
+ if value.nil?
+ is_nullable = self.class.openapi_nullable.include?(attr)
+ next if !is_nullable || (is_nullable && !instance_variable_defined?(:"@#{attr}"))
+ end
+
+ hash[param] = _to_hash(value)
+ end
+ hash
+ end
+
+ # Outputs non-array value in the form of hash
+ # For object, use to_hash. Otherwise, just return the value
+ # @param [Object] value Any valid value
+ # @return [Hash] Returns the value in the form of hash
+ def _to_hash(value)
+ if value.is_a?(Array)
+ value.compact.map { |v| _to_hash(v) }
+ elsif value.is_a?(Hash)
+ {}.tap do |hash|
+ value.each { |k, v| hash[k] = _to_hash(v) }
+ end
+ elsif value.respond_to? :to_hash
+ value.to_hash
+ else
+ value
+ end
+ end
+
+ end
+
+end
diff --git a/generated/activitysmith_openapi/models/live_activity_action.rb b/generated/activitysmith_openapi/models/live_activity_action.rb
index 389bd32..c4f1e42 100644
--- a/generated/activitysmith_openapi/models/live_activity_action.rb
+++ b/generated/activitysmith_openapi/models/live_activity_action.rb
@@ -53,7 +53,7 @@ def self.openapi_types
:'type' => :'LiveActivityActionType',
:'url' => :'String',
:'method' => :'LiveActivityWebhookMethod',
- :'body' => :'Hash'
+ :'body' => :'Object'
}
end
@@ -103,9 +103,7 @@ def initialize(attributes = {})
end
if attributes.key?(:'body')
- if (value = attributes[:'body']).is_a?(Hash)
- self.body = value
- end
+ self.body = attributes[:'body']
end
end
diff --git a/generated/activitysmith_openapi/models/push_notification_action.rb b/generated/activitysmith_openapi/models/push_notification_action.rb
index 84ded6a..f64fe47 100644
--- a/generated/activitysmith_openapi/models/push_notification_action.rb
+++ b/generated/activitysmith_openapi/models/push_notification_action.rb
@@ -52,7 +52,7 @@ def self.openapi_types
:'type' => :'PushNotificationActionType',
:'url' => :'String',
:'method' => :'PushNotificationWebhookMethod',
- :'body' => :'Hash'
+ :'body' => :'Object'
}
end
@@ -102,9 +102,7 @@ def initialize(attributes = {})
end
if attributes.key?(:'body')
- if (value = attributes[:'body']).is_a?(Hash)
- self.body = value
- end
+ self.body = attributes[:'body']
end
end
diff --git a/generated/activitysmith_openapi/models/push_notification_request.rb b/generated/activitysmith_openapi/models/push_notification_request.rb
index 7dd3a89..effcb1b 100644
--- a/generated/activitysmith_openapi/models/push_notification_request.rb
+++ b/generated/activitysmith_openapi/models/push_notification_request.rb
@@ -68,7 +68,7 @@ def self.openapi_types
:'media' => :'String',
:'redirection' => :'String',
:'actions' => :'Array',
- :'payload' => :'Hash',
+ :'payload' => :'Object',
:'badge' => :'Integer',
:'sound' => :'String',
:'target' => :'ChannelTarget'
@@ -125,9 +125,7 @@ def initialize(attributes = {})
end
if attributes.key?(:'payload')
- if (value = attributes[:'payload']).is_a?(Hash)
- self.payload = value
- end
+ self.payload = attributes[:'payload']
end
if attributes.key?(:'badge')
diff --git a/lib/activitysmith/client.rb b/lib/activitysmith/client.rb
index 0ab93bf..707b40e 100644
--- a/lib/activitysmith/client.rb
+++ b/lib/activitysmith/client.rb
@@ -19,6 +19,14 @@ def initialize(api_key:)
@notifications = Notifications.new(OpenapiClient::PushNotificationsApi.new(api_client))
@live_activities = LiveActivities.new(OpenapiClient::LiveActivitiesApi.new(api_client))
@metrics = Metrics.new(OpenapiClient::MetricsApi.new(api_client))
+ @app_icon_badges = OpenapiClient::AppIconBadgesApi.new(api_client)
+ end
+
+ def badge_count(value, channels: nil)
+ request = { badge: value }
+ normalized_channels = normalize_channels(channels)
+ request[:target] = { channels: normalized_channels } unless normalized_channels.empty?
+ @app_icon_badges.update_app_icon_badge_count(request)
end
private
@@ -44,7 +52,8 @@ def generated_client_present?
"OpenapiClient::ApiClient",
"OpenapiClient::PushNotificationsApi",
"OpenapiClient::LiveActivitiesApi",
- "OpenapiClient::MetricsApi"
+ "OpenapiClient::MetricsApi",
+ "OpenapiClient::AppIconBadgesApi"
].reject { |name| constant_defined?(name) }
missing.empty?
@@ -56,5 +65,10 @@ def constant_defined?(name)
rescue NameError
false
end
+
+ def normalize_channels(channels)
+ values = channels.is_a?(String) ? channels.split(",") : Array(channels)
+ values.map { |channel| channel.to_s.strip }.reject(&:empty?)
+ end
end
end
diff --git a/lib/activitysmith/version.rb b/lib/activitysmith/version.rb
index 4d79d17..6795883 100644
--- a/lib/activitysmith/version.rb
+++ b/lib/activitysmith/version.rb
@@ -1,5 +1,5 @@
# frozen_string_literal: true
module ActivitySmith
- VERSION = "1.8.0"
+ VERSION = "1.9.0"
end
diff --git a/test/client_test.rb b/test/client_test.rb
index d5847cc..155ddd0 100644
--- a/test/client_test.rb
+++ b/test/client_test.rb
@@ -44,6 +44,20 @@ def initialize(api_client)
@api_client = api_client
end
end
+
+ class AppIconBadgesApi
+ attr_reader :api_client, :calls
+
+ def initialize(api_client)
+ @api_client = api_client
+ @calls = []
+ end
+
+ def update_app_icon_badge_count(request, opts = {})
+ @calls << [request, opts]
+ request
+ end
+ end
end
class ClientTest < Minitest::Test
@@ -68,6 +82,7 @@ def test_constructs_when_generated_client_is_present
assert_respond_to client.live_activities, :end_stream
refute_nil client.metrics
assert_respond_to client.metrics, :update
+ assert_respond_to client, :badge_count
metrics_api = client.metrics.instance_variable_get(:@api)
assert_equal "ruby-v#{ActivitySmith::VERSION}", metrics_api.api_client.default_headers["X-ActivitySmith-SDK"]
@@ -77,4 +92,22 @@ def test_constructs_when_generated_client_is_present
raise
end
+
+ def test_badge_count_clears_and_targets_channels
+ client = ActivitySmith::Client.new(api_key: "test-api-key")
+ api = client.instance_variable_get(:@app_icon_badges)
+
+ assert_equal({ badge: 0 }, client.badge_count(0))
+ assert_equal(
+ { badge: 3, target: { channels: %w[sales customer-success] } },
+ client.badge_count(3, channels: "sales,customer-success")
+ )
+ assert_equal(
+ [
+ [{ badge: 0 }, {}],
+ [{ badge: 3, target: { channels: %w[sales customer-success] } }, {}]
+ ],
+ api.calls
+ )
+ end
end