import 'package:frosty/constants.dart'; import 'package:json_annotation/json_annotation.dart'; part 'emotes.g.dart'; // * Twitch Emotes * @JsonSerializable(createToJson: false, fieldRename: FieldRename.snake) class EmoteTwitch { final String id; final String name; final String? emoteType; final String? ownerId; const EmoteTwitch( this.id, this.name, this.emoteType, this.ownerId, ); factory EmoteTwitch.fromJson(Map json) => _$EmoteTwitchFromJson(json); } // * BTTV Emotes * @JsonSerializable(createToJson: false) class EmoteBTTV { final String id; final String code; const EmoteBTTV( this.id, this.code, ); factory EmoteBTTV.fromJson(Map json) => _$EmoteBTTVFromJson(json); } @JsonSerializable(createToJson: false) class EmoteBTTVChannel { final List channelEmotes; final List sharedEmotes; const EmoteBTTVChannel( this.channelEmotes, this.sharedEmotes, ); factory EmoteBTTVChannel.fromJson(Map json) => _$EmoteBTTVChannelFromJson(json); } // * FFZ Emotes * @JsonSerializable(createToJson: false, fieldRename: FieldRename.snake) class RoomFFZ { final int set; final ImagesFFZ? vipBadge; final ImagesFFZ? modUrls; const RoomFFZ( this.set, this.vipBadge, this.modUrls, ); factory RoomFFZ.fromJson(Map json) => _$RoomFFZFromJson(json); } @JsonSerializable(createToJson: false) class ImagesFFZ { @JsonKey(name: '1') final String url1x; @JsonKey(name: '2') final String? url2x; @JsonKey(name: '4') final String? url4x; const ImagesFFZ( this.url1x, this.url2x, this.url4x, ); factory ImagesFFZ.fromJson(Map json) => _$ImagesFFZFromJson(json); } @JsonSerializable(createToJson: false) class EmoteFFZ { final String name; final int height; final int width; final ImagesFFZ urls; const EmoteFFZ( this.name, this.height, this.width, this.urls, ); factory EmoteFFZ.fromJson(Map json) => _$EmoteFFZFromJson(json); } @JsonSerializable(createToJson: false, fieldRename: FieldRename.snake) class Emote7TV { final String name; final List visibilitySimple; final List width; final List height; final List> urls; const Emote7TV( this.name, this.visibilitySimple, this.width, this.height, this.urls, ); factory Emote7TV.fromJson(Map json) => _$Emote7TVFromJson(json); } /// The common emote class. @JsonSerializable() class Emote { final String name; final int? width; final int? height; final bool zeroWidth; final String url; final EmoteType type; final String? ownerId; const Emote({ required this.name, this.width, this.height, required this.zeroWidth, required this.url, required this.type, this.ownerId, }); factory Emote.fromTwitch(EmoteTwitch emote, EmoteType type) => Emote( name: emote.name, zeroWidth: false, url: 'https://static-cdn.jtvnw.net/emoticons/v2/${emote.id}/default/dark/3.0', type: type, ownerId: emote.ownerId, ); factory Emote.fromBTTV(EmoteBTTV emote, EmoteType type) => Emote( name: emote.code, zeroWidth: zeroWidthEmotes.contains(emote.code), url: 'https://cdn.betterttv.net/emote/${emote.id}/3x', type: type, ); factory Emote.fromFFZ(EmoteFFZ emote, EmoteType type) => Emote( name: emote.name, zeroWidth: false, width: emote.width, height: emote.height, url: emote.urls.url4x ?? emote.urls.url2x ?? emote.urls.url1x, type: type, ); factory Emote.from7TV(Emote7TV emote, EmoteType type) => Emote( name: emote.name, width: emote.width.first, height: emote.height.first, zeroWidth: emote.visibilitySimple.contains('ZERO_WIDTH'), url: emote.urls[3][1], type: type, ); factory Emote.fromJson(Map json) => _$EmoteFromJson(json); Map toJson() => _$EmoteToJson(this); } enum EmoteType { twitchBits, twitchFollower, twitchSub, twitchGlobal, twitchUnlocked, twitchChannel, ffzGlobal, ffzChannel, bttvGlobal, bttvChannel, bttvShared, sevenTVGlobal, sevenTVChannel; @override String toString() { switch (this) { case EmoteType.twitchBits: return 'Twitch bits emote'; case EmoteType.twitchFollower: return 'Twitch follower emote'; case EmoteType.twitchSub: return 'Twitch sub emote'; case EmoteType.twitchGlobal: return 'Twitch global emote'; case EmoteType.twitchUnlocked: return 'Twitch unlocked emote'; case EmoteType.twitchChannel: return 'Twitch channel emote'; case EmoteType.ffzGlobal: return 'FrankerFaceZ global emote'; case EmoteType.ffzChannel: return 'FrankerFaceZ channel emote'; case EmoteType.bttvGlobal: return 'BetterTTV global emote'; case EmoteType.bttvChannel: return 'BetterTTV channel emote'; case EmoteType.bttvShared: return 'BetterTTV shared emote'; case EmoteType.sevenTVGlobal: return '7TV global emote'; case EmoteType.sevenTVChannel: return '7TV channel emote'; } } }