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
5 changes: 2 additions & 3 deletions android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application
android:label="surf_flutter_summer_school_24"
android:label="change_theme"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher">
<activity
android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTop"
android:taskAffinity=""
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
Expand All @@ -32,7 +31,7 @@
android:value="2" />
</application>
<!-- Required to query activities that can process text, see:
https://developer.android.com/training/package-visibility and
https://developer.android.com/training/package-visibility?hl=en and
https://developer.android.com/reference/android/content/Intent#ACTION_PROCESS_TEXT.

In particular, this is used by the Flutter engine in io.flutter.plugin.text.ProcessTextPlugin. -->
Expand Down
Binary file added assets/fonts/Roboto-Black.ttf
Binary file not shown.
Binary file added assets/fonts/Roboto-BlackItalic.ttf
Binary file not shown.
Binary file added assets/fonts/Roboto-Bold.ttf
Binary file not shown.
Binary file added assets/fonts/Roboto-BoldItalic.ttf
Binary file not shown.
Binary file added assets/fonts/Roboto-Italic.ttf
Binary file not shown.
Binary file added assets/fonts/Roboto-Light.ttf
Binary file not shown.
Binary file added assets/fonts/Roboto-LightItalic.ttf
Binary file not shown.
Binary file added assets/fonts/Roboto-Medium.ttf
Binary file not shown.
Binary file added assets/fonts/Roboto-MediumItalic.ttf
Binary file not shown.
Binary file added assets/fonts/Roboto-Regular.ttf
Binary file not shown.
Binary file added assets/fonts/Roboto-Thin.ttf
Binary file not shown.
Binary file added assets/fonts/Roboto-ThinItalic.ttf
Binary file not shown.
Binary file added assets/images/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/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/3.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/4.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/5.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/6.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/7.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/8.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/lologram.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 16 additions & 0 deletions lib/app/feature/theme/data/theme_repository.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import 'package:surf_flutter_summer_school_24/app/storage/theme/theme_storage.dart';
import 'package:flutter/material.dart';

class ThemeRepository {
final ThemeStorage _themeStorage;

ThemeRepository({required ThemeStorage themStorage}) : _themeStorage = themStorage;

setThemeMode(newThemeMode) async {
await _themeStorage.saveThemeMode(mode: newThemeMode);
}

ThemeMode? getThemeMode() {
return _themeStorage.getThemeMode();
}
}
32 changes: 32 additions & 0 deletions lib/app/feature/theme/di/theme_inherited.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// ! все что ниже - ctrl+v

import 'package:surf_flutter_summer_school_24/app/feature/theme/domain/theme_controller.dart';
import 'package:flutter/material.dart';

class ThemeInherited extends InheritedWidget {


final ThemeController themeController;

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


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'); // ? Почему != (assert-проверка условий)
return result!;
}

@override
bool updateShouldNotify(ThemeInherited oldWidget) => false; // ? зависимые виджеты не уведомляются об изменениях
}
32 changes: 32 additions & 0 deletions lib/app/feature/theme/domain/theme_controller.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// ! все что ниже - ctrl+v

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:surf_flutter_summer_school_24/app/feature/theme/data/theme_repository.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;
}
}
41 changes: 41 additions & 0 deletions lib/app/feature/theme/ui/theme_builder.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// ! все что ниже - ctrl+v

import 'package:surf_flutter_summer_school_24/app/feature/theme/di/theme_inherited.dart';
import 'package:flutter/material.dart';

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

class ThemeBuilder extends StatefulWidget {

final ThemeWidgetBuilder builder;

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


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

class _ThemeBuilderState extends State<ThemeBuilder> {
@override
Widget build(BuildContext context) {
return ValueListenableBuilder<ThemeMode>( // ? че такое ValueListenableBuilder и откуда тот, кто слушает valuenotifier
valueListenable: ThemeInherited.of(context).themeMode, // ? вопрос про ThemeMode в theme_storage
builder: (
builderContext,
themeMode,
_,
) =>
widget.builder( // ? Что такое widget здесь и откуда у него метод builder
builderContext,
themeMode,
),
);
}
}
33 changes: 33 additions & 0 deletions lib/app/my_app.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@

import 'package:flutter/material.dart';
import 'package:surf_flutter_summer_school_24/app/feature/theme/di/theme_inherited.dart';
import 'package:surf_flutter_summer_school_24/app/feature/theme/domain/theme_controller.dart';
import 'package:surf_flutter_summer_school_24/app/feature/theme/ui/theme_builder.dart';
import 'package:surf_flutter_summer_school_24/app/screens/opened_image/opened_image_with_scroll.dart';
import 'package:surf_flutter_summer_school_24/app/screens/start_page/start_page.dart';
import 'package:surf_flutter_summer_school_24/app/uikit/theme/theme_data.dart';

class MainApp extends StatelessWidget {
final ThemeController themeController;
const MainApp({super.key, required this.themeController});

@override
Widget build(BuildContext context) {
return ThemeInherited(
themeController: themeController,
child: ThemeBuilder(builder: (_, themeMode) {
return MaterialApp(
theme: AppThemeData.lightTheme,
darkTheme: AppThemeData.darkTheme,
themeMode: themeMode,
home: const StartPage(),
initialRoute: '/start_page',
routes: {
'/start_page': (context) => const StartPage(),
'/opened_image': (context) => OpenedPhotoWithScroll(themeController: themeController),
},
);
}));
}
}

127 changes: 127 additions & 0 deletions lib/app/screens/opened_image/opened_image_with_scroll.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
import 'package:flutter/material.dart';
import 'package:surf_flutter_summer_school_24/app/feature/theme/di/theme_inherited.dart';
import 'package:surf_flutter_summer_school_24/app/feature/theme/domain/theme_controller.dart';
import 'package:surf_flutter_summer_school_24/app/feature/theme/ui/theme_builder.dart';
import 'package:surf_flutter_summer_school_24/app/storage/images/images.dart';
import 'package:surf_flutter_summer_school_24/app/uikit/theme/theme_data.dart';
import 'package:surf_flutter_summer_school_24/app/uikit/styles/font_styles.dart';


class OpenedPhotoWithScroll extends StatelessWidget {
final ThemeController themeController;
const OpenedPhotoWithScroll({super.key, required this.themeController});

@override
Widget build(BuildContext context) {
return ThemeInherited(
themeController: themeController,
child: ThemeBuilder(builder: (
_, themeMode
){
return MaterialApp(
theme: AppThemeData.lightTheme,
darkTheme: AppThemeData.darkTheme,
themeMode: themeMode,
home: const Page(),

);
}));
}
}


final controller = PageController(
viewportFraction: 0.7,
initialPage: 1,
);


class Page extends StatefulWidget {
const Page({super.key});

@override
State<Page> createState() => _PageState();
}

class _PageState extends State<Page> {
int _currentIndex = 1;

@override
void initState() {
super.initState();
controller.addListener(() {
int newIndex = controller.page?.round() ?? 0;
if (newIndex != _currentIndex) {
setState(() {
_currentIndex = newIndex;
});
}
});
}

@override
Widget build(BuildContext context) {
final dynamicAppBarColorForTextSpan = Theme.of(context).appBarTheme.foregroundColor;
return Scaffold(
appBar: AppBar(
leading: IconButton(onPressed: () { Navigator.of(context).pop(); },
icon: const Icon(Icons.arrow_back)),
title: Expanded(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Center(child: Text('01.01.2021', style: MyCustomStyle.mainTextThin,)),
ElevatedButton(
onPressed: () {ThemeInherited.of(context).switchThemeMode();}, child: const Text('Тема')),
RichText(
text: TextSpan(
children: [
TextSpan(
text: '${_currentIndex + 1}',
style: MyCustomStyle.mainTextBold.copyWith(fontSize: 18, color: dynamicAppBarColorForTextSpan),
),
TextSpan(
text: '/${images.length}',
style: MyCustomStyle.mainTextBoldGrey.copyWith(fontSize: 18, color: Color(0xAAAAAAAA)),
)
]
),
)
]),
),
),
body: PageView.builder(
pageSnapping: false,
controller: controller,
itemCount: images.length,
itemBuilder: (context, index) {

var _scale = _currentIndex == index ? 1.0 : 0.87;

return TweenAnimationBuilder(
duration: const Duration(microseconds: 350),
tween: Tween(begin: _scale, end: _scale),
curve: Curves.ease,
builder: (context, value, child) {
return Transform.scale(
scale: value,
child: child,
);
},
child: Center(
child: Container(
// margin: const EdgeInsets.symmetric(horizontal: 5),
height: 600,
// width: 400,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
image:
DecorationImage(image: images[index], fit: BoxFit.cover),
),
),
),
);
},
));
}
}
31 changes: 31 additions & 0 deletions lib/app/screens/start_page/start_page.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import 'package:flutter/material.dart';

class StartPage extends StatefulWidget {
const StartPage({super.key});

@override
State<StartPage> createState() => _StartPageState();
}

class _StartPageState extends State<StartPage> {
@override
Widget build(BuildContext context) {
// final dynamicAppBarColorForTextSpan = Theme.of(context).appBarTheme.foregroundColor;
return Scaffold(
appBar: AppBar(
// clipBehavior: Clip.none,
leading: null,
title: Center(
child: Image.asset('assets/images/lologram.png')
),
actions: [
IconButton(onPressed: (){}, icon: Icon(Icons.abc_outlined))
],
),
body: FloatingActionButton(
onPressed: () { Navigator.of(context).pushNamed('/opened_image'); },
child: Text('Перейти на фотографию')
),
);
}
}
13 changes: 13 additions & 0 deletions lib/app/storage/images/images.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@

import 'package:flutter/material.dart';

List<AssetImage> images = [
const AssetImage('assets/images/1.jpg'),
const AssetImage('assets/images/2.jpg'),
const AssetImage('assets/images/3.jpg'),
const AssetImage('assets/images/4.jpg'),
const AssetImage('assets/images/5.jpg'),
const AssetImage('assets/images/6.jpg'),
const AssetImage('assets/images/7.jpg'),
const AssetImage('assets/images/8.jpg'),
];
26 changes: 26 additions & 0 deletions lib/app/storage/theme/theme_storage.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import 'package:collection/collection.dart';
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';

enum ThemeStorageKeys {
mode('theme_mode');
final String key;
const ThemeStorageKeys(this.key);
}

class ThemeStorage {
final SharedPreferences _prefs;

ThemeStorage({required SharedPreferences prefs}) : _prefs = prefs;

ThemeMode? getThemeMode(){ // обращаемся в хранилище, потом из ThemeMode достаем то же самое, что и в хранилище сейчас
final storedName = _prefs.getString(ThemeStorageKeys.mode.key);
if (storedName?.isEmpty ?? true) return null;
return ThemeMode.values.firstWhereOrNull((themeMode) => themeMode.name == storedName);
}

Future<void> saveThemeMode({required ThemeMode mode}){
return _prefs.setString(ThemeStorageKeys.mode.key, mode.name);
}
}

Loading