class PollAnswer { final int answerId; final String text; final int voteCount; final double rate; final List votes; final bool mine; const PollAnswer({ required this.answerId, required this.text, this.voteCount = 0, this.rate = 0, this.votes = const [], this.mine = false, }); } class Poll { final int pollId; final String title; final int settings; final int version; final int total; final List answers; final List voterPreviewIds; const Poll({ required this.pollId, required this.title, this.settings = 0, this.version = 0, this.total = 0, this.answers = const [], this.voterPreviewIds = const [], }); bool get isMultiple => settings & 0x1 != 0; bool get hasMyVote => answers.any((a) => a.mine); bool votedBy(int userId) => answers.any((a) => a.mine || a.votes.contains(userId)); static List _parseVoterIds(dynamic votes) { if (votes is! List) return const []; final ids = []; for (final v in votes) { if (v is int) { ids.add(v); } else if (v is Map && v['userId'] is int) { ids.add(v['userId'] as int); } } return ids; } Poll withStateMap(Map stateMap) { return _buildFromState( pollId: pollId, title: title, settings: settings, version: version, answerIdsAndTexts: [for (final a in answers) (a.answerId, a.text)], stateMap: stateMap, ); } factory Poll.fromServerMap(Map map) { final state = map['state']; final stateMap = state is Map ? state : const {}; final answerIdsAndTexts = <(int, String)>[]; final rawAnswers = map['answers']; if (rawAnswers is List) { for (final a in rawAnswers) { if (a is! Map) continue; answerIdsAndTexts.add(( a['answerId'] as int? ?? 0, a['text']?.toString() ?? '', )); } } return _buildFromState( pollId: map['pollId'] as int? ?? 0, title: map['title']?.toString() ?? '', settings: map['settings'] as int? ?? 0, version: map['version'] as int? ?? 0, answerIdsAndTexts: answerIdsAndTexts, stateMap: stateMap, ); } static Poll _buildFromState({ required int pollId, required String title, required int settings, required int version, required List<(int, String)> answerIdsAndTexts, required Map stateMap, }) { final resultsById = {}; final result = stateMap['result']; if (result is List) { for (final r in result) { if (r is Map && r['answerId'] is int) { resultsById[r['answerId'] as int] = r; } } } final answers = []; for (final (id, text) in answerIdsAndTexts) { final res = resultsById[id]; answers.add( PollAnswer( answerId: id, text: text, voteCount: (res?['voteCount'] as num?)?.toInt() ?? 0, rate: (res?['rate'] as num?)?.toDouble() ?? 0, votes: _parseVoterIds(res?['votes']), mine: ((res?['options'] as num?)?.toInt() ?? 0) & 0x1 != 0, ), ); } return Poll( pollId: pollId, title: title, settings: settings, version: version, total: (stateMap['total'] as num?)?.toInt() ?? 0, answers: answers, voterPreviewIds: (stateMap['voterPreviewIds'] as List?)?.whereType().toList() ?? const [], ); } }