Initial Flutter app

This commit is contained in:
Ruslan Bakiev
2026-05-05 11:58:38 +07:00
commit 80b8f1cc18
112 changed files with 5732 additions and 0 deletions

View File

@@ -0,0 +1,78 @@
import 'package:flutter/material.dart';
import 'package:latlong2/latlong.dart';
enum ExperienceEmotion { comfort, energy, curiosity, tenderness, focus }
extension ExperienceEmotionText on ExperienceEmotion {
String get label {
return switch (this) {
ExperienceEmotion.comfort => 'уют',
ExperienceEmotion.energy => 'энергия',
ExperienceEmotion.curiosity => 'любопытство',
ExperienceEmotion.tenderness => 'нежность',
ExperienceEmotion.focus => 'собранность',
};
}
IconData get icon {
return switch (this) {
ExperienceEmotion.comfort => Icons.weekend_outlined,
ExperienceEmotion.energy => Icons.bolt_outlined,
ExperienceEmotion.curiosity => Icons.explore_outlined,
ExperienceEmotion.tenderness => Icons.spa_outlined,
ExperienceEmotion.focus => Icons.center_focus_strong_outlined,
};
}
}
class DishSignal {
const DishSignal({
required this.name,
required this.reason,
required this.texture,
});
final String name;
final String reason;
final String texture;
}
class ProfileFacet {
const ProfileFacet({required this.name, required this.value});
final String name;
final String value;
}
class ExperienceAuthor {
const ExperienceAuthor({required this.name, required this.facets});
final String name;
final List<ProfileFacet> facets;
}
class PlaceExperience {
const PlaceExperience({
required this.id,
required this.placeName,
required this.neighborhood,
required this.coordinate,
required this.emotion,
required this.intensity,
required this.context,
required this.dish,
required this.author,
required this.createdLabel,
});
final String id;
final String placeName;
final String neighborhood;
final LatLng coordinate;
final ExperienceEmotion emotion;
final int intensity;
final String context;
final DishSignal dish;
final ExperienceAuthor author;
final String createdLabel;
}

View File

@@ -0,0 +1,174 @@
import 'package:flutter/material.dart';
import 'package:latlong2/latlong.dart';
enum PlaceTrait {
calm,
alive,
cozy,
cold,
status,
simple,
free,
formal,
private,
open,
social,
solo,
beautiful,
neutral,
unusual,
clear,
focused,
transit,
}
extension PlaceTraitText on PlaceTrait {
String get label {
return switch (this) {
PlaceTrait.calm => 'спокойное',
PlaceTrait.alive => 'живое',
PlaceTrait.cozy => 'уютное',
PlaceTrait.cold => 'холодное',
PlaceTrait.status => 'статусное',
PlaceTrait.simple => 'простое',
PlaceTrait.free => 'свободное',
PlaceTrait.formal => 'формальное',
PlaceTrait.private => 'приватное',
PlaceTrait.open => 'открытое',
PlaceTrait.social => 'для общения',
PlaceTrait.solo => 'для себя',
PlaceTrait.beautiful => 'красивое',
PlaceTrait.neutral => 'нейтральное',
PlaceTrait.unusual => 'необычное',
PlaceTrait.clear => 'понятное',
PlaceTrait.focused => 'помогает собраться',
PlaceTrait.transit => 'транзитное',
};
}
}
enum UserIntent { exhale, date, meet, focus, move, surprise, alone, impress }
extension UserIntentText on UserIntent {
String get title {
return switch (this) {
UserIntent.exhale => 'выдохнуть',
UserIntent.date => 'свидание',
UserIntent.meet => 'встретиться',
UserIntent.focus => 'поработать',
UserIntent.move => 'движ',
UserIntent.surprise => 'удивиться',
UserIntent.alone => 'побыть одному',
UserIntent.impress => 'привести кого-то',
};
}
String get subtitle {
return switch (this) {
UserIntent.exhale => 'тихо, мягко, без давления',
UserIntent.date => 'красиво и лично',
UserIntent.meet => 'общение без лишней формальности',
UserIntent.focus => 'собраться и не выпадать',
UserIntent.move => 'живо, шумно, с энергией',
UserIntent.surprise => 'не как обычно',
UserIntent.alone => 'быть в своем ритме',
UserIntent.impress => 'место должно держать момент',
};
}
IconData get icon {
return switch (this) {
UserIntent.exhale => Icons.air_outlined,
UserIntent.date => Icons.favorite_border,
UserIntent.meet => Icons.forum_outlined,
UserIntent.focus => Icons.center_focus_strong_outlined,
UserIntent.move => Icons.bolt_outlined,
UserIntent.surprise => Icons.auto_awesome_outlined,
UserIntent.alone => Icons.person_outline,
UserIntent.impress => Icons.diamond_outlined,
};
}
Set<PlaceTrait> get traits {
return switch (this) {
UserIntent.exhale => {PlaceTrait.calm, PlaceTrait.cozy, PlaceTrait.solo},
UserIntent.date => {
PlaceTrait.private,
PlaceTrait.beautiful,
PlaceTrait.social,
},
UserIntent.meet => {PlaceTrait.social, PlaceTrait.free, PlaceTrait.alive},
UserIntent.focus => {
PlaceTrait.focused,
PlaceTrait.calm,
PlaceTrait.neutral,
},
UserIntent.move => {PlaceTrait.alive, PlaceTrait.open, PlaceTrait.social},
UserIntent.surprise => {
PlaceTrait.unusual,
PlaceTrait.alive,
PlaceTrait.open,
},
UserIntent.alone => {PlaceTrait.solo, PlaceTrait.free, PlaceTrait.calm},
UserIntent.impress => {
PlaceTrait.status,
PlaceTrait.beautiful,
PlaceTrait.private,
},
};
}
}
class PlaceRecommendation {
const PlaceRecommendation({
required this.id,
required this.name,
required this.area,
required this.photoUrls,
required this.coordinate,
required this.traits,
});
final String id;
final String name;
final String area;
final List<String> photoUrls;
final LatLng coordinate;
final Set<PlaceTrait> traits;
String get coverPhotoUrl => photoUrls.first;
}
class VoiceReviewDraft {
const VoiceReviewDraft({
required this.placeName,
required this.duration,
required this.extractedTraits,
required this.suggestedIntents,
required this.evidence,
});
final String placeName;
final Duration duration;
final Set<PlaceTrait> extractedTraits;
final Set<UserIntent> suggestedIntents;
final List<String> evidence;
bool get isLongEnough => duration.inSeconds >= 30;
VoiceReviewDraft copyWith({
String? placeName,
Duration? duration,
Set<PlaceTrait>? extractedTraits,
Set<UserIntent>? suggestedIntents,
List<String>? evidence,
}) {
return VoiceReviewDraft(
placeName: placeName ?? this.placeName,
duration: duration ?? this.duration,
extractedTraits: extractedTraits ?? this.extractedTraits,
suggestedIntents: suggestedIntents ?? this.suggestedIntents,
evidence: evidence ?? this.evidence,
);
}
}