Skip to content

Commit

Permalink
Merge branch 'dev' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
TesteurManiak committed Feb 21, 2022
2 parents cc07c99 + b22a256 commit e8b214d
Show file tree
Hide file tree
Showing 13 changed files with 276 additions and 1 deletion.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
* Added method `getGlobalEmotes`
* Added method `getEmoteSets`
* Added method `getChannelChatBadges`
* Added method `getGlobalChatBadges`
* Added methode `getChatSettings`

## [0.5.1] - 27/10/2021

Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,9 @@ Now you are ready to use the methods implemented in [Supported Endpoints](#suppo
* [x] Get Global Emotes
* [x] Get Emote Sets
* [x] Get Channel Chat Badges
* [ ] Get Global Chat Badges
* [x] Get Global Chat Badges
* [x] Get Chat Settings
* [ ] Update Chat Settings

### Clips

Expand Down
44 changes: 44 additions & 0 deletions lib/src/client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import 'errors/exceptions.dart';
import 'extensions/enum_extensions.dart';
import 'models/twitch_channel_editor.dart';
import 'models/twitch_chat_badge.dart';
import 'models/twitch_chat_settings.dart';
import 'models/twitch_game_analytic.dart';
import 'models/twitch_start_commercial.dart';
import 'providers/twitch_dio_provider.dart';
Expand Down Expand Up @@ -1121,4 +1122,47 @@ class TwitchClient {
.map<TwitchChatBadge>(TwitchChatBadge.fromJson)
.toList();
}

/// Gets a list of chat badges that can be used in chat for any channel.
Future<List<TwitchChatBadge>> getGlobalChatBadges() async {
final data = await twitchHttpClient.getCall<Map<String, dynamic>>(
['chat', 'badges', 'global'],
);
return (data['data'] as Iterable)
.cast<Map<String, dynamic>>()
.map<TwitchChatBadge>(TwitchChatBadge.fromJson)
.toList();
}

/// Gets the broadcaster’s chat settings.
///
/// To include the `non_moderator_chat_delay` or `non_moderator_chat_delay_duration`
/// settings in the response, you must specify a User access token with scope
/// set to [TwitchApiScope.moderatorReadChatSettings].
///
/// `broadcasterId`: The ID of the broadcaster whose chat settings you want to
/// get.
///
/// `moderatorId`: Required only to access the `non_moderator_chat_delay` or
/// `non_moderator_chat_delay_duration` settings. The ID of a user that has
/// permission to moderate the broadcaster’s chat room. This ID must match the
/// user ID associated with the user OAuth token. If the broadcaster wants to
/// get their own settings (instead of having the moderator do it), set this
/// parameter to the broadcaster’s ID, too.
Future<List<TwitchChatSettings>> getChatSettings({
required String broadcasterId,
String? moderatorId,
}) async {
final data = await twitchHttpClient.getCall<Map<String, dynamic>>(
['chat', 'settings'],
queryParameters: <String, String>{
'broadcaster_id': broadcasterId,
if (moderatorId != null) 'moderator_id': moderatorId,
},
);
return (data['data'] as Iterable)
.cast<Map<String, dynamic>>()
.map<TwitchChatSettings>(TwitchChatSettings.fromJson)
.toList();
}
}
3 changes: 3 additions & 0 deletions lib/src/models/twitch_api_scopes.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ enum TwitchApiScope {
channelReadEditors,
channelReadRedemptions,
channelReadSubscriptions,
moderatorReadChatSettings,
userReadEmail,
}

Expand All @@ -32,6 +33,8 @@ extension TwitchApiScopeModifier on TwitchApiScope {
return 'channel:read:redemptions';
case TwitchApiScope.channelReadSubscriptions:
return 'channel:read:subscriptions';
case TwitchApiScope.moderatorReadChatSettings:
return 'moderator:read:chat_settings';
case TwitchApiScope.userReadEmail:
return 'user:read:email';
}
Expand Down
112 changes: 112 additions & 0 deletions lib/src/models/twitch_chat_settings.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
class TwitchChatSettings {
/// The ID of the broadcaster specified in the request.
final String broadcasterId;

/// A Boolean value that determines whether chat messages must contain only
/// emotes. Is `true`, if only messages that are 100% emotes are allowed;
/// otherwise, `false`.
final bool emoteMode;

/// A Boolean value that determines whether the broadcaster restricts the chat
/// room to followers only, based on how long they’ve followed.
///
/// Is `true`, if the broadcaster restricts the chat room to followers only;
/// otherwise, `false`.
///
/// See [followerModeDuration] for how long the followers must have followed
/// the broadcaster to participate in the chat room.
final bool followerMode;

/// The length of time, in minutes, that the followers must have followed the
/// broadcaster to participate in the chat room. See [followerMode].
///
/// Is `null` if [followerMode] is `false`.
final int? followerModeDuration;

/// The moderator’s ID. The response includes this field only if the request
/// specifies a User access token that includes the
/// `TwitchApiScope.moderatorReadChatSettings` scope.
final String? moderatorId;

/// A Boolean value that determines whether the broadcaster adds a short delay
/// before chat messages appear in the chat room. This gives chat moderators
/// and bots a chance to remove them before viewers can see the message.
///
/// Is `true`, if the broadcaster applies a delay; otherwise, `false`.
///
/// See [nonModeratorChatDelayDuration] for the length of the delay.
///
/// The response includes this field only if the request specifies a User
/// access token that includes the `TwitchApiScope.moderatorReadChatSettings`
/// scope.
final bool nonModeratorChatDelay;

/// The amount of time, in seconds, that messages are delayed from appearing
/// in chat. See [nonModeratorChatDelay].
///
/// Is `null` if [nonModeratorChatDelay] is `false`.
///
/// The response includes this field only if the request specifies a User
/// access token that includes the `TwitchApiScope.moderatorReadChatSettings`
/// scope.
final int? nonModeratorChatDelayDuration;

/// A Boolean value that determines whether the broadcaster limits how often
/// users in the chat room are allowed to send messages.
///
/// Is `true`, if the broadcaster applies a delay; otherwise, `false`.
///
/// See [slowModeWaitTime] for the delay.
final bool slowMode;

/// The amount of time, in seconds, that users need to wait between sending
/// messages. See [slowMode].
///
/// Is `null` if [slowMode] is `false`.
final int? slowModeWaitTime;

/// A Boolean value that determines whether only users that subscribe to the
/// broadcaster’s channel can talk in the chat room.
///
/// Is `true`, if the broadcaster restricts the chat room to subscribers only;
/// otherwise, `false`.
final bool subscriberMode;

/// A Boolean value that determines whether the broadcaster requires users to
/// post only unique messages in the chat room.
///
/// Is `true`, if the broadcaster requires unique messages only; otherwise,
/// `false`.
final bool uniqueChatMode;

TwitchChatSettings({
required this.broadcasterId,
required this.emoteMode,
required this.followerMode,
required this.followerModeDuration,
required this.moderatorId,
required this.nonModeratorChatDelay,
required this.nonModeratorChatDelayDuration,
required this.slowMode,
required this.slowModeWaitTime,
required this.subscriberMode,
required this.uniqueChatMode,
});

factory TwitchChatSettings.fromJson(Map<String, dynamic> json) {
return TwitchChatSettings(
broadcasterId: json['broadcaster_id'] as String,
emoteMode: json['emote_mode'] as bool,
followerMode: json['follower_mode'] as bool,
followerModeDuration: json['follower_mode_duration'] as int?,
moderatorId: json['moderator_id'] as String?,
nonModeratorChatDelay: json['non_moderator_chat_delay'] as bool,
nonModeratorChatDelayDuration:
json['non_moderator_chat_delay_duration'] as int?,
slowMode: json['slow_mode'] as bool,
slowModeWaitTime: json['slow_mode_wait_time'] as int?,
subscriberMode: json['subscriber_mode'] as bool,
uniqueChatMode: json['unique_chat_mode'] as bool,
);
}
}
17 changes: 17 additions & 0 deletions test/client/get_chat_settings_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import 'package:test/test.dart';

import '../utils/twitch_mock_client.dart';

void main() {
final client = TwitchMockClient();

group('getChatSettings', () {
const tBroadcasterId = '1234';

test('1', () async {
final settings =
await client.getChatSettings(broadcasterId: tBroadcasterId);
expect(settings.length, 1);
});
});
}
14 changes: 14 additions & 0 deletions test/client/get_global_chat_badges_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import 'package:test/test.dart';

import '../utils/twitch_mock_client.dart';

void main() {
final client = TwitchMockClient();

group('getGlobalChatBadges', () {
test('1', () async {
final badges = await client.getGlobalChatBadges();
expect(badges.length, 1);
});
});
}
9 changes: 9 additions & 0 deletions test/errors/exceptions_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,13 @@ void main() {
expect(tException.toString(), 'TwitchException: $tMessage');
});
});

group('TwitchGetExtensionAnalyticsException', () {
const tMessage = 'get extension analytics failed';
const tException = TwitchGetExtensionAnalyticsException(tMessage);

test('toString', () {
expect(tException.toString(), 'TwitchException: $tMessage');
});
});
}
4 changes: 4 additions & 0 deletions test/models/twitch_api_scopes_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ void main() {
TwitchApiScope.channelReadSubscriptions.string,
'channel:read:subscriptions',
);
expect(
TwitchApiScope.moderatorReadChatSettings.string,
'moderator:read:chat_settings',
);
expect(
TwitchApiScope.userReadEmail.string,
'user:read:email',
Expand Down
30 changes: 30 additions & 0 deletions test/models/twitch_chat_settings_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import 'dart:convert';

import 'package:test/test.dart';
import 'package:twitch_api/src/models/twitch_chat_settings.dart';

import '../utils/test_utils.dart';

void main() {
group('TwitchChatSettings', () {
test('parse: get_chat_settings.json', () async {
final json =
jsonDecode(await readFileStringAsync('get_chat_settings.json'))
as Map<String, dynamic>;
final settingsJson =
(json['data'] as Iterable).first as Map<String, dynamic>;
final settings = TwitchChatSettings.fromJson(settingsJson);

expect(settings.broadcasterId, '713936733');
expect(settings.slowMode, false);
expect(settings.slowModeWaitTime, isNull);
expect(settings.followerMode, true);
expect(settings.followerModeDuration, 0);
expect(settings.subscriberMode, false);
expect(settings.emoteMode, false);
expect(settings.uniqueChatMode, false);
expect(settings.nonModeratorChatDelay, true);
expect(settings.nonModeratorChatDelayDuration, 4);
});
});
}
16 changes: 16 additions & 0 deletions test/test_resources/get_chat_settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"data": [
{
"broadcaster_id": "713936733",
"slow_mode": false,
"slow_mode_wait_time": null,
"follower_mode": true,
"follower_mode_duration": 0,
"subscriber_mode": false,
"emote_mode": false,
"unique_chat_mode": false,
"non_moderator_chat_delay": true,
"non_moderator_chat_delay_duration": 4
}
]
}
15 changes: 15 additions & 0 deletions test/test_resources/get_global_chat_badges.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"data": [
{
"set_id": "vip",
"versions": [
{
"id": "1",
"image_url_1x": "https://static-cdn.jtvnw.net/badges/v1/b817aba4-fad8-49e2-b88a-7cc744dfa6ec/1",
"image_url_2x": "https://static-cdn.jtvnw.net/badges/v1/b817aba4-fad8-49e2-b88a-7cc744dfa6ec/2",
"image_url_4x": "https://static-cdn.jtvnw.net/badges/v1/b817aba4-fad8-49e2-b88a-7cc744dfa6ec/3"
}
]
}
]
}
7 changes: 7 additions & 0 deletions test/utils/twitch_mock_http_client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,13 @@ class TwitchMockHttpClient extends TwitchHttpClient {
return jsonDecode(
await readFileStringAsync('get_channel_chat_badges.json'),
) as T;
case 'chat/badges/global':
return jsonDecode(
await readFileStringAsync('get_global_chat_badges.json'),
) as T;
case 'chat/settings':
return jsonDecode(await readFileStringAsync('get_chat_settings.json'))
as T;
default:
throw 'Bad Request: Query Parameter missing or invalid $path';
}
Expand Down

0 comments on commit e8b214d

Please sign in to comment.