Решение: Flutter приложение со списком пользователей из API
Представляю полноценное решение с использованием Riverpod для state management, Dio для HTTP запросов, Freezed для моделей и обработкой всех состояний загрузки.
1. Модели данных (lib/models/user_model.dart)
import "package:freezed_annotation/freezed_annotation.dart";
part "user_model.freezed.dart";
part "user_model.g.dart";
@freezed
class User with _$User {
const factory User({
required int id,
required String name,
required String email,
required String phone,
required String username,
required String website,
required Address address,
required Company company,
}) = _User;
factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
}
@freezed
class Address with _$Address {
const factory Address({
required String street,
required String city,
required String zipcode,
required Geo geo,
}) = _Address;
Решение: Flutter Todo List приложение
Представляю полноценное решение для приложения управления задачами с использованием Provider для state management и Hive для локального хранилища.
Архитектура решения
Слои приложения:
1. Модель данных (lib/models/todo.dart)
import "package:hive/hive.dart";
part "todo.g.dart";
@HiveType(typeId: 0)
class Todo extends HiveObject {
@HiveField(0)
late String id;
@HiveField(1)
late String title;
@HiveField(2)
late bool isCompleted;
@HiveField(3)
late DateTime createdAt;
Todo({
required this.id,
required this.title,
this.isCompleted = false,
required this.createdAt,
});
}
2. Репозиторий для работы с Hive (lib/data/todo_repository.dart)
import "package:hive/hive.dart";
import "../models/todo.dart";
Решение: Flutter бесконечный скроллируемый список с пагинацией
Представляю полное решение с автоматической загрузкой при достижении конца списка, pull-to-refresh и скелетон-лоадером.
1. Модель данных (lib/models/post_model.dart)
import "package:freezed_annotation/freezed_annotation.dart";
part "post_model.freezed.dart";
part "post_model.g.dart";
@freezed
class Post with _\$Post {
const factory Post({
required int id,
required int userId,
required String title,
required String body,
}) = _Post;
factory Post.fromJson(Map<String, dynamic> json) => _\$PostFromJson(json);
}
2. Сервис API (lib/services/post_service.dart)
import "package:dio/dio.dart";
import "../models/post_model.dart";
class PostService {
static const String _baseUrl = "https://jsonplaceholder.typicode.com";
static const int _postsPerPage = 20;
late final Dio _dio;
Flutter Bottom Navigation с сохранением состояния
Полное решение с вложенной навигацией и сохранением состояния каждого таба.
Архитектура
Компоненты
Функциональность
Решение: Flutter поиск с debounce и историей
Представляю полное решение с debounce, отменой предыдущих запросов, историей поиска и подсветкой найденного текста.
1. Модель данных (lib/models/search_models.dart)
import "package:freezed_annotation/freezed_annotation.dart";
part "search_models.freezed.dart";
part "search_models.g.dart";
@freezed
class User with _\$User {
const factory User({
required int id,
required String name,
required String email,
required String username,
}) = _User;
factory User.fromJson(Map<String, dynamic> json) => _\$UserFromJson(json);
}
@freezed
class SearchState with _\$SearchState {
const factory SearchState.idle({
@Default([]) List<String> history,
}) = _Idle;
const factory SearchState.loading({
required String query,
@Default([]) List<String> history,
}) = _Loading;
Решение: Профиль пользователя с аватаром
Полнофункциональный экран профиля с выбором, кроппингом и загрузкой аватара.
Модель пользователя
class User {
final String id;
final String name;
final String email;
final String? avatarPath;
final DateTime createdAt;
final DateTime? updatedAt;
User({
required this.id,
required this.name,
required this.email,
this.avatarPath,
required this.createdAt,
this.updatedAt,
});
User copyWith({
String? id,
String? name,
String? email,
String? avatarPath,
DateTime? createdAt,
DateTime? updatedAt,
}) {
return User(
id: id ?? this.id,
name: name ?? this.name,
email: email ?? this.email,
avatarPath: avatarPath ?? this.avatarPath,
createdAt: createdAt ?? this.createdAt,
updatedAt: updatedAt ?? this.updatedAt,
);
}
}
Контроллер профиля
Flutter приложение заметок с Firebase
Полное решение с Firebase Auth, Firestore и синхронизацией.
Компоненты решения
Структура данных
Каждая заметка содержит:
Основные файлы
Решение: Приложение Прогноза Погоды на Flutter
Архитектура и структура проекта
Построим приложение по принципам Clean Architecture с разделением на слои:
lib/
├── data/
│ ├── models/ # Data models
│ ├── repositories/ # Реализация репозиториев
│ └── datasources/ # API и локальное хранилище
├── domain/
│ ├── entities/ # Бизнес-сущности
│ ├── repositories/ # Абстракции
│ └── usecases/ # Бизнес-логика
├── presentation/
│ ├── pages/
│ ├── widgets/
│ ├── controllers/ # State management
│ └── theme/
└── core/
└── utils/ # Утилиты
Модели данных
// domain/entities/weather.dart
class Weather {
final String city;
final double temperature;
final String description;
final String iconCode;
final double humidity;
final double windSpeed;
final DateTime timestamp;
Решение: Flutter экран авторизации с валидацией форм
Представляю полное решение с реактивной валидацией, использованием Riverpod для state management и красивой анимацией переходов.
1. Модели форм (lib/models/auth_models.dart)
import "package:freezed_annotation/freezed_annotation.dart";
part "auth_models.freezed.dart";
part "auth_models.g.dart";
@freezed
class LoginForm with _\$LoginForm {
const factory LoginForm({
@Default("") String email,
@Default("") String password,
@Default(false) bool rememberMe,
}) = _LoginForm;
}
@freezed
class SignupForm with _\$SignupForm {
const factory SignupForm({
@Default("") String email,
@Default("") String password,
@Default("") String confirmPassword,
}) = _SignupForm;
}
@freezed
class ValidationError with _\$ValidationError {
const factory ValidationError({
String? email,
String? password,
String? confirmPassword,
}) = _ValidationError;
const ValidationError._();
Решение: Flutter кастомный виджет рейтинга со звёздами
Представляю полнофункциональный виджет с поддержкой половинных звёзд, анимацией, свайпом и режимом только для чтения.
1. Основной виджет RatingWidget (lib/widgets/rating_widget.dart)
import "package:flutter/material.dart";
class RatingWidget extends StatefulWidget {
final double rating;
final int starCount;
final double size;
final Color activeColor;
final Color inactiveColor;
final ValueChanged<double>? onRatingChanged;
final bool readOnly;
final IconData? customIcon;
final bool allowHalfRating;
Решение: Чат-интерфейс на Flutter
Архитектура и структура
Построим полнофункциональный чат с поддержкой статусов сообщений, индикаторов печати и группировкой по датам.
Модель сообщения и статусы
// domain/entities/message.dart
enum MessageStatus { sending, sent, delivered, read }
enum MessageType { text, image }
class Message {
final String id;
final String text;
final DateTime timestamp;
final bool isMe;
final MessageStatus status;
final MessageType type;
final String? imageUrl;
final String senderId;
final String recipientId;
Message({
required this.id,
required this.text,
required this.timestamp,
required this.isMe,
this.status = MessageStatus.sent,
this.type = MessageType.text,
this.imageUrl,
required this.senderId,
required this.recipientId,
});
Решение: Flutter счётчик с использованием BLoC паттерна
Представляю полное решение с flutter_bloc, разделением на Events и States, а также unit-тестами.
1. События (lib/bloc/counter_event.dart)
part of "counter_bloc.dart";
abstract class CounterEvent extends Equatable {
const CounterEvent();
@override
List<Object> get props => [];
}
class IncrementEvent extends CounterEvent {
const IncrementEvent();
}
class DecrementEvent extends CounterEvent {
const DecrementEvent();
}
class ResetEvent extends CounterEvent {
const ResetEvent();
}
2. Состояния (lib/bloc/counter_state.dart)
part of "counter_bloc.dart";
abstract class CounterState extends Equatable {
final int value;
const CounterState(this.value);
@override
List<Object> get props => [value];
}
class CounterInitial extends CounterState {
const CounterInitial() : super(0);
}
Flutter калькулятор с научным режимом
Полнофункциональный калькулятор с историей и поддержкой сложных операций.
Компоненты
Функциональность
Архитектура
Решение: Flutter анимированная карточка с 3D переворотом
Представляю полное решение с использованием AnimationController и Transform для создания эффекта 3D переворота.
1. Кастомный виджет FlipCard (lib/widgets/flip_card.dart)
import "package:flutter/material.dart";
import "dart:math" as math;
class FlipCard extends StatefulWidget {
final Widget front;
final Widget back;
final Duration duration;
final VoidCallback? onFlip;
final VoidCallback? onUnflip;
const FlipCard({
required this.front,
required this.back,
this.duration = const Duration(milliseconds: 500),
this.onFlip,
this.onUnflip,
Key? key,
}) : super(key: key);
@override
State<FlipCard> createState() => _FlipCardState();
}
class _FlipCardState extends State<FlipCard>
with SingleTickerProviderStateMixin {
late AnimationController _controller;
late Animation<double> _animation;
bool _isFront = true;
Решение: Экран Онбординга на Flutter
Полнофункциональный экран онбординга с анимациями, параллаксом и автоматической прокруткой между слайдами.
Основной компонент OnboardingPage
Страница состоит из PageView для свайпинга, индикаторов прогресса и кнопок навигации.
class OnboardingPage extends StatefulWidget {
@override
_OnboardingPageState createState() => _OnboardingPageState();
}
class _OnboardingPageState extends State<OnboardingPage> with TickerProviderStateMixin {
late PageController pageController;
int currentIndex = 0;
Решение: Flutter галерея изображений с полноэкранным просмотром
Представляю полное решение с GridView, Hero анимацией, свайпом и pinch-to-zoom.
1. Модель данных (lib/models/photo_model.dart)
import "package:freezed_annotation/freezed_annotation.dart";
part "photo_model.freezed.dart";
part "photo_model.g.dart";
@freezed
class Photo with _\$Photo {
const factory Photo({
required int id,
required String author,
@JsonKey(name: "download_url") required String downloadUrl,
required String url,
required int width,
required int height,
}) = _Photo;
factory Photo.fromJson(Map<String, dynamic> json) => _\$PhotoFromJson(json);
}
2. Сервис загрузки изображений (lib/services/photo_service.dart)
import "package:dio/dio.dart";
import "../models/photo_model.dart";
class PhotoService {
static const String _baseUrl = "https://picsum.photos/v2";
late final Dio _dio;
Решение: Экран Настроек с SharedPreferences
Полнофункциональный экран настроек с группировкой, предпросмотром и сохранением.
Модель настроек
class AppSettings {
final bool darkMode;
final String language;
final bool notificationsEnabled;
final double fontSize;
AppSettings({
this.darkMode = false,
this.language = 'ru',
this.notificationsEnabled = true,
this.fontSize = 1.0,
});
Map<String, dynamic> toJson() {
return {
'darkMode': darkMode,
'language': language,
'notificationsEnabled': notificationsEnabled,
'fontSize': fontSize,
};
}
factory AppSettings.fromJson(Map<String, dynamic> json) {
return AppSettings(
darkMode: json['darkMode'] ?? false,
language: json['language'] ?? 'ru',
notificationsEnabled: json['notificationsEnabled'] ?? true,
fontSize: json['fontSize'] ?? 1.0,
);
}
}
Сервис настроек
Flutter конвертер валют
Полное решение с API интеграцией, историей и offline режимом.
Компоненты
Функциональность
API
Лучше всего использовать:
Эндпойнт: GET /v6/{API_KEY}/latest/{base_currency}
Решение: Кастомный Progress Indicator
Создаём круговой индикатор прогресса с поддержкой градиентов и анимаций.
CustomPainter для рисования
Используем Canvas для отрисовки окружности и прогрессивной дуги:
class CircularProgressPainter extends CustomPainter {
final double progress;
final Color progressColor;
final Color backgroundColor;
final double strokeWidth;
CircularProgressPainter({
required this.progress,
required this.progressColor,
required this.backgroundColor,
required this.strokeWidth,
});
@override
void paint(Canvas canvas, Size size) {
final center = Offset(size.width / 2, size.height / 2);
final radius = (size.width - strokeWidth) / 2;
// Фоновая окружность
canvas.drawCircle(
center,
radius,
Paint()
..color = backgroundColor
..style = PaintingStyle.stroke
..strokeWidth = strokeWidth,
);
Решение: Flutter Drag and Drop список с анимацией
Представляю полное решение с перетаскиванием, удалением свайпом, haptic feedback и функцией undo.
1. Модель данных (lib/models/task_model.dart)
import "package:freezed_annotation/freezed_annotation.dart";
import "package:uuid/uuid.dart";
part "task_model.freezed.dart";
part "task_model.g.dart";
@freezed
class Task with _\$Task {
const factory Task({
@Default("") String id,
required String title,
required String description,
@Default(false) bool isCompleted,
}) = _Task;
factory Task.fromJson(Map<String, dynamic> json) => _\$TaskFromJson(json);
factory Task.create(String title, String description) {
return Task(
id: const Uuid().v4(),
title: title,
description: description,
);
}
}
2. Провайдеры (lib/providers/task_providers.dart)
import "package:flutter_riverpod/flutter_riverpod.dart";
import "../models/task_model.dart";
Решение: Приложение Таймера с Обратным Отсчётом
Архитектура приложения
Таймер будет реализован с использованием State Management (GetX) и Local Notifications для фоновой работы.
Модель данных таймера
// domain/entities/timer_entity.dart
class TimerEntity {
final int totalSeconds;
final int remainingSeconds;
final bool isRunning;
final DateTime createdAt;
final String? name;
TimerEntity({
required this.totalSeconds,
required this.remainingSeconds,
required this.isRunning,
required this.createdAt,
this.name,
});
Решение: Игра Memory на Flutter
Полнофункциональная игра на запоминание с уровнями сложности, анимациями и таблицей результатов.
Модели данных
enum GameDifficulty { easy, medium, hard }
enum CardTheme { animals, food, flags }
class Card {
final int id;
final String symbol;
final bool isFlipped;
final bool isMatched;
Card({
required this.id,
required this.symbol,
this.isFlipped = false,
this.isMatched = false,
});
Card copyWith({
int? id,
String? symbol,
bool? isFlipped,
bool? isMatched,
}) {
return Card(
id: id ?? this.id,
symbol: symbol ?? this.symbol,
isFlipped: isFlipped ?? this.isFlipped,
isMatched: isMatched ?? this.isMatched,
);
}
}
class GameResult {
final int moves;
final int time;
final GameDifficulty difficulty;
final DateTime timestamp;
GameResult({
required this.moves,
required this.time,
required this.difficulty,
required this.timestamp,
});
}
Flutter регистрация DNS-стажёра
Полное решение с валидацией формы, маской ввода и API интеграцией.
Компоненты
Поля формы
Валидация
Функциональность