import 'package:flutter/material.dart'; import 'package:latlong2/latlong.dart'; class AppUser { const AppUser({ required this.id, required this.telegramId, required this.username, required this.firstName, required this.lastName, required this.photoUrl, required this.languageCode, required this.isAdmin, }); factory AppUser.fromJson(Map json) { return AppUser( id: json['id'] as String, telegramId: json['telegramId'] as String, username: json['username'] as String?, firstName: json['firstName'] as String?, lastName: json['lastName'] as String?, photoUrl: json['photoUrl'] as String?, languageCode: json['languageCode'] as String?, isAdmin: json['isAdmin'] as bool? ?? false, ); } final String id; final String telegramId; final String? username; final String? firstName; final String? lastName; final String? photoUrl; final String? languageCode; final bool isAdmin; } class VoiceExperienceDebug { const VoiceExperienceDebug({ required this.id, required this.placeName, required this.userName, required this.status, required this.durationSeconds, required this.transcript, required this.analysis, required this.createdAt, }); factory VoiceExperienceDebug.fromJson(Map json) { final place = json['place'] as Map; final user = json['user'] as Map?; final firstName = user?['firstName'] as String?; final username = user?['username'] as String?; final telegramId = user?['telegramId'] as String?; return VoiceExperienceDebug( id: json['id'] as String, placeName: place['name'] as String, userName: firstName?.trim().isNotEmpty == true ? firstName! : username?.trim().isNotEmpty == true ? '@$username' : telegramId ?? '', status: json['status'] as String, durationSeconds: json['durationSeconds'] as int, transcript: json['transcript'] as String?, analysis: json['analysis'] as Map?, createdAt: DateTime.parse(json['createdAt'] as String), ); } final String id; final String placeName; final String userName; final String status; final int durationSeconds; final String? transcript; final Map? analysis; final DateTime createdAt; } enum PlaceTrait { calm, dynamic, intimate, open, solo, group, reset, impress, transit, clean, expressive, } extension PlaceTraitText on PlaceTrait { String get label { return switch (this) { PlaceTrait.calm => 'спокойное', PlaceTrait.dynamic => 'живое', PlaceTrait.intimate => 'камерное', PlaceTrait.open => 'открытое', PlaceTrait.solo => 'для себя', PlaceTrait.group => 'для компании', PlaceTrait.reset => 'выдохнуть', PlaceTrait.impress => 'впечатлить', PlaceTrait.transit => 'транзитное', PlaceTrait.clean => 'чистое', PlaceTrait.expressive => 'выразительное', }; } IconData get icon { return switch (this) { PlaceTrait.calm => Icons.air_outlined, PlaceTrait.dynamic => Icons.bolt_outlined, PlaceTrait.intimate => Icons.lock_outline, PlaceTrait.open => Icons.public_outlined, PlaceTrait.solo => Icons.person_outline, PlaceTrait.group => Icons.forum_outlined, PlaceTrait.reset => Icons.spa_outlined, PlaceTrait.impress => Icons.diamond_outlined, PlaceTrait.transit => Icons.near_me_outlined, PlaceTrait.clean => Icons.wb_sunny_outlined, PlaceTrait.expressive => Icons.auto_awesome_outlined, }; } } class PlaceRecommendation { const PlaceRecommendation({ required this.id, required this.googlePlaceId, required this.name, required this.area, required this.photoUrls, required this.coordinate, required this.traits, required this.googlePrimaryType, required this.googleTypes, }); final String id; final String googlePlaceId; final String name; final String area; final List photoUrls; final LatLng coordinate; final Set traits; final String? googlePrimaryType; final List googleTypes; String get coverPhotoUrl => photoUrls.first; } class VoiceReviewDraft { const VoiceReviewDraft({ required this.placeName, required this.duration, required this.extractedTraits, required this.evidence, }); final String placeName; final Duration duration; final Set extractedTraits; final List evidence; bool get isLongEnough => duration.inSeconds >= 30; VoiceReviewDraft copyWith({ String? placeName, Duration? duration, Set? extractedTraits, List? evidence, }) { return VoiceReviewDraft( placeName: placeName ?? this.placeName, duration: duration ?? this.duration, extractedTraits: extractedTraits ?? this.extractedTraits, evidence: evidence ?? this.evidence, ); } } class TelegramBotLogin { const TelegramBotLogin({ required this.token, required this.botUrl, required this.expiresAt, }); factory TelegramBotLogin.fromJson(Map json) { return TelegramBotLogin( token: json['token'] as String, botUrl: json['botUrl'] as String, expiresAt: DateTime.parse(json['expiresAt'] as String), ); } final String token; final String botUrl; final DateTime expiresAt; } class TelegramBotLoginSession { const TelegramBotLoginSession({ required this.sessionToken, required this.user, }); factory TelegramBotLoginSession.fromJson(Map json) { return TelegramBotLoginSession( sessionToken: json['sessionToken'] as String, user: AppUser.fromJson(json['user'] as Map), ); } final String sessionToken; final AppUser user; }