Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ migrate_working_dir/
.pub-cache/
.pub/
/build/
/linux

# Symbolication related
app.*.symbols
Expand Down
Binary file added assets/images/Default_madoka_magica_art_0.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/images/Default_madoka_magica_art_1.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/images/Default_madoka_magica_art_2.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/images/Default_madoka_magica_art_3.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/images/Mahou_Shoujo_Madoka_Magika.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/images/smile.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions devtools_options.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
description: This file stores settings for Dart & Flutter DevTools.
documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states
extensions:
1 change: 1 addition & 0 deletions lib/analysis_options.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
include: package:flutter_lints/flutter.yaml
17 changes: 17 additions & 0 deletions lib/data/data_sources/theme_storage.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import 'package:shared_preferences/shared_preferences.dart';
import '../../domain/models/custom_theme_mode.dart';

class ThemeStorage {
final SharedPreferences prefs;

ThemeStorage({required this.prefs});

CustomThemeMode loadTheme() {
var themeIndex = prefs.getInt('themeMode') ?? 0;
return CustomThemeModeExtension.fromIndex(themeIndex);
}

void saveTheme(CustomThemeMode themeMode) {
prefs.setInt('themeMode', themeMode.index);
}
}
4 changes: 4 additions & 0 deletions lib/data/mocks/image_mock_data.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import '../../domain/models/image_model.dart';
import '../models/image_model.dart';

final List<ImageModel> mockImageList = imgList;
65 changes: 65 additions & 0 deletions lib/data/models/image_model.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import '../../domain/models/image_model.dart';

final List<ImageModel> imgList = [
ImageModel(
dateOfCreate: '01.03.2023',
imagePath: 'assets/images/Default_madoka_magica_art_0.jpg'),
ImageModel(
dateOfCreate: '02.05.2023',
imagePath: 'assets/images/Default_madoka_magica_art_1.jpg'),
ImageModel(
dateOfCreate: '03.06.2023',
imagePath: 'assets/images/Default_madoka_magica_art_2.jpg'),
ImageModel(
dateOfCreate: '05.06.2023',
imagePath: 'assets/images/Default_madoka_magica_art_3.jpg'),
ImageModel(
dateOfCreate: '09.06.2023',
imagePath:
'assets/images/Default_madoka_magica_from_anime_Madoka_Magica_0.jpg'),
ImageModel(
dateOfCreate: '02.07.2023',
imagePath:
'assets/images/Default_madoka_magica_from_anime_Madoka_Magica_1.jpg'),
ImageModel(
dateOfCreate: '03.07.2023',
imagePath:
'assets/images/Default_madoka_magica_from_anime_Madoka_Magica_2.jpg'),
ImageModel(
dateOfCreate: '01.08.2023',
imagePath:
'assets/images/Default_madoka_magica_from_anime_Madoka_Magica_3.jpg'),
ImageModel(
dateOfCreate: '01.08.2023',
imagePath:
'assets/images/Default_madoka_magica_from_anime_Madoka_Magica_with_bow_0.jpg'),
ImageModel(
dateOfCreate: '01.03.2023',
imagePath:
'assets/images/Default_madoka_magica_from_anime_Madoka_Magica_with_bow_1.jpg'),
ImageModel(
dateOfCreate: '01.03.2023',
imagePath:
'assets/images/Default_madoka_magica_from_anime_Madoka_Magica_with_bow_2.jpg'),
ImageModel(
dateOfCreate: '01.03.2023',
imagePath:
'assets/images/Default_madoka_magica_from_anime_Madoka_Magica_with_bow_3.jpg'),
ImageModel(
dateOfCreate: '01.03.2023',
imagePath:
'assets/images/Default_madoka_magica_from_anime_Madoka_Magica_with_bow_in_spa_0.jpg'),
ImageModel(
dateOfCreate: '01.03.2023',
imagePath:
'assets/images/Default_madoka_magica_from_anime_Madoka_Magica_with_bow_in_spa_1.jpg'),
ImageModel(
dateOfCreate: '01.03.2023',
imagePath:
'assets/images/Default_madoka_magica_from_anime_Madoka_Magica_with_bow_in_spa_2.jpg'),
ImageModel(
dateOfCreate: '01.03.2023',
imagePath:
'assets/images/Default_madoka_magica_from_anime_Madoka_Magica_with_bow_in_spa_3.jpg'),
];

3 changes: 3 additions & 0 deletions lib/devtools_options.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
description: This file stores settings for Dart & Flutter DevTools.
documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states
extensions:
81 changes: 81 additions & 0 deletions lib/domain/controllers/photo_controller.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import 'package:flutter/material.dart';
import 'dart:io';
import 'package:image_picker/image_picker.dart';
import '../../presentation/pages/error_page.dart';
import '../models/image_model.dart';

class PhotoController with ChangeNotifier {
List<ImageModel> photos = [];
bool isLoading = false;
String? errorMessage;

PhotoController() {
_loadInitialPhotos();
}

Future<void> _loadInitialPhotos() async {
photos = ImageModel.getAllImages();
notifyListeners();
}

Future<void> pickImage(BuildContext context, ImageSource source) async {
final ImagePicker picker = ImagePicker();
final XFile? image = await picker.pickImage(source: source);
if (image != null) {
// Проверяем, существует ли файл, перед тем как пытаться его сохранить
if (await _fileExists(context, File(image.path))) {
await saveImageLocally(context, File(image.path));
}
} else {
setError(context, 'Изображение не было выбрано.');
}
}

Future<bool> _fileExists(BuildContext context, File file) async {
try {
if (!await file.exists()) {
throw Exception('Asset not found');
}
return true;
} catch (e) {
setError(context, 'Ошибка при загрузке изображения: ${e.toString()}');
return false;
}
}

Future<void> saveImageLocally(BuildContext context, File image) async {
setLoading(true);
try {
final fileName = '${DateTime.now().millisecondsSinceEpoch}.jpg';
final savedImage = await image.copy('assets/images/$fileName');

final newImage = ImageModel(
dateOfCreate: DateTime.now().toIso8601String(),
imagePath: savedImage.path,
);
photos.add(newImage);
ImageModel.addImage(newImage);
notifyListeners();
} catch (e) {
setError(context, 'Ошибка при сохранении изображения: ${e.toString()}');
}
setLoading(false);
}

void setLoading(bool value) {
isLoading = value;
notifyListeners();
}

void setError(BuildContext context, String? message) {
errorMessage = message;
notifyListeners();
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => ErrorPage(
errorMessage: message ?? 'Произошла ошибка. Попробуйте еще раз.',
),
),
);
}
}
20 changes: 20 additions & 0 deletions lib/domain/controllers/theme_controller.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import 'package:flutter/material.dart';
import '../repositories/theme_repository.dart';
import '../models/custom_theme_mode.dart';

class ThemeController extends ChangeNotifier {
final ThemeRepository themeRepository;
late CustomThemeMode _currentThemeMode;

ThemeController({required this.themeRepository}) {
_currentThemeMode = themeRepository.loadTheme();
}

CustomThemeMode get themeMode => _currentThemeMode;

void setThemeMode(CustomThemeMode themeMode) {
_currentThemeMode = themeMode;
themeRepository.saveTheme(themeMode);
notifyListeners();
}
}
26 changes: 26 additions & 0 deletions lib/domain/models/custom_theme_mode.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
enum CustomThemeMode {
light,
dark,
}

extension CustomThemeModeExtension on CustomThemeMode {
int get index {
switch (this) {
case CustomThemeMode.light:
return 0;
case CustomThemeMode.dark:
return 1;
}
}

static CustomThemeMode fromIndex(int index) {
switch (index) {
case 0:
return CustomThemeMode.light;
case 1:
return CustomThemeMode.dark;
default:
return CustomThemeMode.light;
}
}
}
18 changes: 18 additions & 0 deletions lib/domain/models/image_model.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import '../../data/models/image_model.dart';

class ImageModel {
final String dateOfCreate;
final String imagePath;

ImageModel({required this.dateOfCreate, required this.imagePath});

static final List<ImageModel> _images = imgList;

static List<ImageModel> getAllImages() {
return _images;
}

static void addImage(ImageModel image) {
_images.add(image);
}
}
12 changes: 12 additions & 0 deletions lib/domain/repositories/theme_repository.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import '../models/custom_theme_mode.dart';
import '../../data/data_sources/theme_storage.dart';

class ThemeRepository {
final ThemeStorage themeStorage;

ThemeRepository({required this.themeStorage});

CustomThemeMode loadTheme() => themeStorage.loadTheme();

void saveTheme(CustomThemeMode themeMode) => themeStorage.saveTheme(themeMode);
}
22 changes: 22 additions & 0 deletions lib/feature/theme/data/theme_repository.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import 'package:change_theme/storage/theme/theme_storage.dart';
import 'package:flutter/material.dart';

class ThemeRepository {
final ThemeStorage _themeStorage;

ThemeRepository({
required ThemeStorage themeStorage,
}) : _themeStorage = themeStorage;

Future<void> setThemeMode(
ThemeMode newThemeMode,
) async {
await _themeStorage.saveThemeMode(
mode: newThemeMode,
);
}

ThemeMode? getThemeMode() {
return _themeStorage.getThemeMode();
}
}
27 changes: 27 additions & 0 deletions lib/feature/theme/di/theme_inherited.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import 'package:change_theme/feature/theme/domain/theme_controller.dart';
import 'package:flutter/material.dart';

class ThemeInherited extends InheritedWidget {
const ThemeInherited({
super.key,
required this.themeController,
required super.child,
});

final ThemeController themeController;

static ThemeController? maybeOf(BuildContext context) {
return context
.dependOnInheritedWidgetOfExactType<ThemeInherited>()
?.themeController;
}

static ThemeController of(BuildContext context) {
final ThemeController? result = maybeOf(context);
assert(result != null, 'No MyThemeInherited found in context');
return result!;
}

@override
bool updateShouldNotify(ThemeInherited oldWidget) => false;
}
30 changes: 30 additions & 0 deletions lib/feature/theme/domain/theme_controller.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import 'package:change_theme/feature/theme/data/theme_repository.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';

class ThemeController {
final ThemeRepository _themeRepository;

ThemeController({
required ThemeRepository themeRepository,
}) : _themeRepository = themeRepository;

late final ValueNotifier<ThemeMode> _themeMode = ValueNotifier<ThemeMode>(
_themeRepository.getThemeMode() ?? ThemeMode.system,
);

ValueListenable<ThemeMode> get themeMode => _themeMode;

Future<void> setThemeMode(ThemeMode newThemeMode) async {
if (newThemeMode == _themeMode.value) return;
await _themeRepository.setThemeMode(newThemeMode);
_themeMode.value = newThemeMode;
}

Future<void> switchThemeMode() async {
final newThemeMode =
_themeMode.value != ThemeMode.light ? ThemeMode.light : ThemeMode.dark;
await _themeRepository.setThemeMode(newThemeMode);
_themeMode.value = newThemeMode;
}
}
37 changes: 37 additions & 0 deletions lib/feature/theme/ui/theme_builder.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import 'package:change_theme/feature/theme/di/theme_inherited.dart';
import 'package:flutter/material.dart';

typedef ThemeWidgetBuilder = Widget Function(
BuildContext context,
ThemeMode themeMode,
);

class ThemeBuilder extends StatefulWidget {
const ThemeBuilder({
required this.builder,
super.key,
});

final ThemeWidgetBuilder builder;

@override
State<ThemeBuilder> createState() => _ThemeBuilderState();
}

class _ThemeBuilderState extends State<ThemeBuilder> {
@override
Widget build(BuildContext context) {
return ValueListenableBuilder<ThemeMode>(
valueListenable: ThemeInherited.of(context).themeMode,
builder: (
builderContext,
themeMode,
_,
) =>
widget.builder(
builderContext,
themeMode,
),
);
}
}
Loading