210 lines
6.6 KiB
Dart
210 lines
6.6 KiB
Dart
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||
import 'package:latlong2/latlong.dart';
|
||
|
||
import '../models/experience_models.dart';
|
||
|
||
final experienceControllerProvider =
|
||
NotifierProvider<ExperienceController, ExperienceState>(
|
||
ExperienceController.new,
|
||
);
|
||
|
||
class ExperienceState {
|
||
const ExperienceState({
|
||
required this.experiences,
|
||
required this.selectedExperienceId,
|
||
required this.filterEmotion,
|
||
required this.profile,
|
||
});
|
||
|
||
final List<PlaceExperience> experiences;
|
||
final String? selectedExperienceId;
|
||
final ExperienceEmotion? filterEmotion;
|
||
final ExperienceAuthor profile;
|
||
|
||
List<PlaceExperience> get visibleExperiences {
|
||
final emotion = filterEmotion;
|
||
if (emotion == null) {
|
||
return experiences;
|
||
}
|
||
return experiences.where((item) => item.emotion == emotion).toList();
|
||
}
|
||
|
||
PlaceExperience? get selectedExperience {
|
||
for (final experience in experiences) {
|
||
if (experience.id == selectedExperienceId) {
|
||
return experience;
|
||
}
|
||
}
|
||
return visibleExperiences.isEmpty ? null : visibleExperiences.first;
|
||
}
|
||
|
||
ExperienceState copyWith({
|
||
List<PlaceExperience>? experiences,
|
||
String? selectedExperienceId,
|
||
bool clearSelection = false,
|
||
ExperienceEmotion? filterEmotion,
|
||
bool clearFilter = false,
|
||
ExperienceAuthor? profile,
|
||
}) {
|
||
return ExperienceState(
|
||
experiences: experiences ?? this.experiences,
|
||
selectedExperienceId: clearSelection
|
||
? null
|
||
: selectedExperienceId ?? this.selectedExperienceId,
|
||
filterEmotion: clearFilter ? null : filterEmotion ?? this.filterEmotion,
|
||
profile: profile ?? this.profile,
|
||
);
|
||
}
|
||
}
|
||
|
||
class ExperienceController extends Notifier<ExperienceState> {
|
||
@override
|
||
ExperienceState build() {
|
||
final experiences = _seedExperiences();
|
||
return ExperienceState(
|
||
experiences: experiences,
|
||
selectedExperienceId: experiences.first.id,
|
||
filterEmotion: null,
|
||
profile: const ExperienceAuthor(
|
||
name: 'Руслан',
|
||
facets: [
|
||
ProfileFacet(name: 'темп', value: 'спокойно, без очередей'),
|
||
ProfileFacet(name: 'еда', value: 'яркое блюдо важнее кухни'),
|
||
ProfileFacet(
|
||
name: 'контекст',
|
||
value: 'работа днем, прогулки вечером',
|
||
),
|
||
],
|
||
),
|
||
);
|
||
}
|
||
|
||
void selectExperience(String id) {
|
||
state = state.copyWith(selectedExperienceId: id);
|
||
}
|
||
|
||
void setEmotionFilter(ExperienceEmotion? emotion) {
|
||
if (emotion == null) {
|
||
state = state.copyWith(clearFilter: true);
|
||
return;
|
||
}
|
||
final nextVisible = state.experiences.firstWhere(
|
||
(item) => item.emotion == emotion,
|
||
orElse: () => state.experiences.first,
|
||
);
|
||
state = state.copyWith(
|
||
filterEmotion: emotion,
|
||
selectedExperienceId: nextVisible.id,
|
||
);
|
||
}
|
||
|
||
void addExperience({
|
||
required String placeName,
|
||
required String dishName,
|
||
required ExperienceEmotion emotion,
|
||
required LatLng coordinate,
|
||
required String context,
|
||
}) {
|
||
final experience = PlaceExperience(
|
||
id: 'local-${DateTime.now().microsecondsSinceEpoch}',
|
||
placeName: placeName.trim().isEmpty ? 'Новое место' : placeName.trim(),
|
||
neighborhood: 'рядом',
|
||
coordinate: coordinate,
|
||
emotion: emotion,
|
||
intensity: 3,
|
||
context: context.trim().isEmpty ? 'личная заметка' : context.trim(),
|
||
dish: DishSignal(
|
||
name: dishName.trim().isEmpty ? 'блюдо' : dishName.trim(),
|
||
reason: 'стоит проверить лично',
|
||
texture: 'новый сигнал',
|
||
),
|
||
author: state.profile,
|
||
createdLabel: 'сейчас',
|
||
);
|
||
|
||
state = state.copyWith(
|
||
experiences: [experience, ...state.experiences],
|
||
selectedExperienceId: experience.id,
|
||
clearFilter: true,
|
||
);
|
||
}
|
||
|
||
List<PlaceExperience> _seedExperiences() {
|
||
const author = ExperienceAuthor(
|
||
name: 'Mira',
|
||
facets: [
|
||
ProfileFacet(name: 'темп', value: 'медленно'),
|
||
ProfileFacet(name: 'еда', value: 'текстура'),
|
||
ProfileFacet(name: 'настроение', value: 'тихое внимание'),
|
||
],
|
||
);
|
||
|
||
return const [
|
||
PlaceExperience(
|
||
id: 'secret-garden',
|
||
placeName: 'Secret Garden',
|
||
neighborhood: 'District 1',
|
||
coordinate: LatLng(10.7752, 106.7009),
|
||
emotion: ExperienceEmotion.comfort,
|
||
intensity: 4,
|
||
context: 'крыша, зелень, хороший разговор',
|
||
dish: DishSignal(
|
||
name: 'caramelized pork clay pot',
|
||
reason: 'мягко собирает вечер',
|
||
texture: 'густой соус, рис, тепло',
|
||
),
|
||
author: author,
|
||
createdLabel: 'вчера',
|
||
),
|
||
PlaceExperience(
|
||
id: 'banh-mi-huynh-hoa',
|
||
placeName: 'Banh Mi Huynh Hoa',
|
||
neighborhood: 'District 1',
|
||
coordinate: LatLng(10.7716, 106.6920),
|
||
emotion: ExperienceEmotion.energy,
|
||
intensity: 5,
|
||
context: 'быстро, плотно, без церемоний',
|
||
dish: DishSignal(
|
||
name: 'banh mi dac biet',
|
||
reason: 'если хочется прямого удара вкуса',
|
||
texture: 'хруст, паштет, травы',
|
||
),
|
||
author: author,
|
||
createdLabel: '3 дня назад',
|
||
),
|
||
PlaceExperience(
|
||
id: 'the-workshop',
|
||
placeName: 'The Workshop',
|
||
neighborhood: 'District 1',
|
||
coordinate: LatLng(10.7740, 106.7042),
|
||
emotion: ExperienceEmotion.focus,
|
||
intensity: 4,
|
||
context: 'ноутбук, кофе, два часа ясности',
|
||
dish: DishSignal(
|
||
name: 'egg coffee',
|
||
reason: 'сладкая пауза между задачами',
|
||
texture: 'крем, горечь, плотность',
|
||
),
|
||
author: author,
|
||
createdLabel: 'на неделе',
|
||
),
|
||
PlaceExperience(
|
||
id: 'oc-dao',
|
||
placeName: 'Oc Dao',
|
||
neighborhood: 'District 1',
|
||
coordinate: LatLng(10.7607, 106.6898),
|
||
emotion: ExperienceEmotion.curiosity,
|
||
intensity: 5,
|
||
context: 'пробовать руками, спорить, заказывать еще',
|
||
dish: DishSignal(
|
||
name: 'grilled scallops',
|
||
reason: 'блюдо ведет сильнее, чем место',
|
||
texture: 'дым, масло, арахис',
|
||
),
|
||
author: author,
|
||
createdLabel: 'месяц назад',
|
||
),
|
||
];
|
||
}
|
||
}
|