final improvements
added internet permission in manifest added unique app bar titles for each section fixed card layout fixed card details page layout added appbar button for toggling dark mode
This commit is contained in:
parent
1a863ee7f7
commit
f0a17af845
@ -1,4 +1,5 @@
|
|||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<application
|
<application
|
||||||
android:label="Crypto Exchange"
|
android:label="Crypto Exchange"
|
||||||
android:name="${applicationName}"
|
android:name="${applicationName}"
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
"mainAppBarTitle": "Cryptocurrency Exchange",
|
"mainAppBarTitle": "Cryptocurrency Exchange",
|
||||||
"detailsPageAppBarTitle": "Cryptocurrency info",
|
"detailsPageAppBarTitle": "Cryptocurrency info",
|
||||||
|
"favouritesPageAppBarTitle": "Favourites",
|
||||||
"settingsPageAppBarTitle": "Settings",
|
"settingsPageAppBarTitle": "Settings",
|
||||||
|
|
||||||
"searchHint": "Search",
|
"searchHint": "Search",
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
"mainAppBarTitle": "Криптобиржа",
|
"mainAppBarTitle": "Криптобиржа",
|
||||||
"detailsPageAppBarTitle": "Сведения о валюте",
|
"detailsPageAppBarTitle": "Сведения о валюте",
|
||||||
|
"favouritesPageAppBarTitle": "Избранное",
|
||||||
"settingsPageAppBarTitle": "Настройки",
|
"settingsPageAppBarTitle": "Настройки",
|
||||||
|
|
||||||
"searchHint": "Поиск",
|
"searchHint": "Поиск",
|
||||||
@ -13,7 +14,7 @@
|
|||||||
|
|
||||||
"settingsLanguage": "Язык",
|
"settingsLanguage": "Язык",
|
||||||
|
|
||||||
"navigationHome": "Главная",
|
"navigationHome": "Главная",
|
||||||
"navigationFavourites": "Избранное",
|
"navigationFavourites": "Избранное",
|
||||||
"navigationSettings": "Настройки"
|
"navigationSettings": "Настройки"
|
||||||
}
|
}
|
@ -107,6 +107,12 @@ abstract class AppLocale {
|
|||||||
/// **'Cryptocurrency info'**
|
/// **'Cryptocurrency info'**
|
||||||
String get detailsPageAppBarTitle;
|
String get detailsPageAppBarTitle;
|
||||||
|
|
||||||
|
/// No description provided for @favouritesPageAppBarTitle.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Favourites'**
|
||||||
|
String get favouritesPageAppBarTitle;
|
||||||
|
|
||||||
/// No description provided for @settingsPageAppBarTitle.
|
/// No description provided for @settingsPageAppBarTitle.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
|
@ -12,6 +12,9 @@ class AppLocaleEn extends AppLocale {
|
|||||||
@override
|
@override
|
||||||
String get detailsPageAppBarTitle => 'Cryptocurrency info';
|
String get detailsPageAppBarTitle => 'Cryptocurrency info';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get favouritesPageAppBarTitle => 'Favourites';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get settingsPageAppBarTitle => 'Settings';
|
String get settingsPageAppBarTitle => 'Settings';
|
||||||
|
|
||||||
|
@ -12,6 +12,9 @@ class AppLocaleRu extends AppLocale {
|
|||||||
@override
|
@override
|
||||||
String get detailsPageAppBarTitle => 'Сведения о валюте';
|
String get detailsPageAppBarTitle => 'Сведения о валюте';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get favouritesPageAppBarTitle => 'Избранное';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get settingsPageAppBarTitle => 'Настройки';
|
String get settingsPageAppBarTitle => 'Настройки';
|
||||||
|
|
||||||
|
@ -15,9 +15,16 @@ void main() {
|
|||||||
runApp(const MyApp());
|
runApp(const MyApp());
|
||||||
}
|
}
|
||||||
|
|
||||||
class MyApp extends StatelessWidget {
|
class MyApp extends StatefulWidget {
|
||||||
const MyApp({super.key});
|
const MyApp({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<MyApp> createState() => _MyAppState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _MyAppState extends State<MyApp> {
|
||||||
|
bool isDarkMode = false;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BlocProvider<FavouritesBloc>(
|
return BlocProvider<FavouritesBloc>(
|
||||||
@ -33,8 +40,12 @@ class MyApp extends StatelessWidget {
|
|||||||
localizationsDelegates: AppLocale.localizationsDelegates,
|
localizationsDelegates: AppLocale.localizationsDelegates,
|
||||||
supportedLocales: AppLocale.supportedLocales,
|
supportedLocales: AppLocale.supportedLocales,
|
||||||
theme: ThemeData(
|
theme: ThemeData(
|
||||||
colorScheme: ColorScheme.fromSeed(seedColor: Colors.indigoAccent),
|
colorScheme: ColorScheme.fromSeed(
|
||||||
|
seedColor: Colors.indigoAccent,
|
||||||
|
brightness: isDarkMode ? Brightness.dark : Brightness.light,
|
||||||
|
),
|
||||||
useMaterial3: true,
|
useMaterial3: true,
|
||||||
|
brightness: isDarkMode ? Brightness.dark : Brightness.light,
|
||||||
),
|
),
|
||||||
debugShowCheckedModeBanner: false,
|
debugShowCheckedModeBanner: false,
|
||||||
home: RepositoryProvider<CryptoRepository>(
|
home: RepositoryProvider<CryptoRepository>(
|
||||||
@ -43,7 +54,10 @@ class MyApp extends StatelessWidget {
|
|||||||
child: BlocProvider<HomeBloc>(
|
child: BlocProvider<HomeBloc>(
|
||||||
lazy: false,
|
lazy: false,
|
||||||
create: (context) => HomeBloc(context.read<CryptoRepository>()),
|
create: (context) => HomeBloc(context.read<CryptoRepository>()),
|
||||||
child: const MainScaffold(),
|
child: MainScaffold(
|
||||||
|
toggleDarkMode: _toggleDarkMode,
|
||||||
|
isDarkModeSelected: isDarkMode,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -52,6 +66,12 @@ class MyApp extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _toggleDarkMode() {
|
||||||
|
setState(() {
|
||||||
|
isDarkMode = !isDarkMode;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
String _getLangCode(String fullLocaleName) {
|
String _getLangCode(String fullLocaleName) {
|
||||||
int index = fullLocaleName.indexOf('_');
|
int index = fullLocaleName.indexOf('_');
|
||||||
return index != -1 ? fullLocaleName.substring(0, index) : fullLocaleName;
|
return index != -1 ? fullLocaleName.substring(0, index) : fullLocaleName;
|
||||||
|
@ -14,19 +14,25 @@ class DetailsPage extends StatelessWidget {
|
|||||||
title: Text(context.locale.detailsPageAppBarTitle),
|
title: Text(context.locale.detailsPageAppBarTitle),
|
||||||
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
|
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
|
||||||
),
|
),
|
||||||
body: Column(
|
body: Padding(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
padding: const EdgeInsets.only(left: 20, right: 20, top: 30),
|
||||||
children: [
|
child: Column(
|
||||||
Padding(
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
padding: const EdgeInsets.only(bottom: 16),
|
children: [
|
||||||
child: Image.network(data.imageUrl ?? ''),
|
Center(
|
||||||
),
|
child: Padding(
|
||||||
Padding(
|
padding: const EdgeInsets.only(bottom: 40),
|
||||||
padding: const EdgeInsets.only(bottom: 4),
|
child: Image.network(data.imageUrl ?? ''),
|
||||||
child: Text(data.title, style: Theme.of(context).textTheme.headlineLarge),
|
),
|
||||||
),
|
),
|
||||||
Text(data.currentPrice, style: Theme.of(context).textTheme.bodyLarge),
|
Padding(
|
||||||
],
|
padding: const EdgeInsets.only(bottom: 8),
|
||||||
|
child: Text(data.title, style: Theme.of(context).textTheme.headlineLarge),
|
||||||
|
),
|
||||||
|
Text(data.currentPrice, style: Theme.of(context).textTheme.bodyLarge),
|
||||||
|
Text(data.priceChange, style: Theme.of(context).textTheme.labelLarge),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -54,7 +54,7 @@ class _FavouritesPageState extends State<FavouritesPage> {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: EdgeInsets.only(top: MediaQuery.of(context).padding.top),
|
padding: EdgeInsets.only(top: 12),
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
CardsList(
|
CardsList(
|
||||||
@ -65,7 +65,10 @@ class _FavouritesPageState extends State<FavouritesPage> {
|
|||||||
),
|
),
|
||||||
BlocBuilder<HomeBloc, HomeState>(
|
BlocBuilder<HomeBloc, HomeState>(
|
||||||
builder: (context, state) => state.isPaginationLoading
|
builder: (context, state) => state.isPaginationLoading
|
||||||
? const CircularProgressIndicator()
|
? const Padding(
|
||||||
|
padding: EdgeInsets.all(12),
|
||||||
|
child: CircularProgressIndicator(),
|
||||||
|
)
|
||||||
: const SizedBox.shrink(),
|
: const SizedBox.shrink(),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -112,7 +115,7 @@ class _FavouritesPageState extends State<FavouritesPage> {
|
|||||||
|
|
||||||
void _onNextPage() {
|
void _onNextPage() {
|
||||||
final bloc = context.read<HomeBloc>();
|
final bloc = context.read<HomeBloc>();
|
||||||
if (!bloc.state.isPaginationLoading) {
|
if (!bloc.state.isPaginationLoading && !bloc.state.isAllPagesLoaded) {
|
||||||
bloc.add(HomeLoadFavouritesDataEvent(
|
bloc.add(HomeLoadFavouritesDataEvent(
|
||||||
ids: favouritesIds,
|
ids: favouritesIds,
|
||||||
nextPage: bloc.state.data?.nextPage,
|
nextPage: bloc.state.data?.nextPage,
|
||||||
|
@ -12,6 +12,8 @@ class HomeBloc extends Bloc<HomeEvent, HomeState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _onLoadData(HomeLoadDataEvent event, Emitter<HomeState> emit) async {
|
Future<void> _onLoadData(HomeLoadDataEvent event, Emitter<HomeState> emit) async {
|
||||||
|
const int pageSize = 20;
|
||||||
|
|
||||||
if (event.nextPage == null) {
|
if (event.nextPage == null) {
|
||||||
emit(state.copyWith(isLoading: true));
|
emit(state.copyWith(isLoading: true));
|
||||||
} else {
|
} else {
|
||||||
@ -23,10 +25,16 @@ class HomeBloc extends Bloc<HomeEvent, HomeState> {
|
|||||||
final data = await repo.loadData(
|
final data = await repo.loadData(
|
||||||
search: event.search,
|
search: event.search,
|
||||||
page: event.nextPage ?? 1,
|
page: event.nextPage ?? 1,
|
||||||
|
pageSize: pageSize,
|
||||||
onError: (e) => error = e,
|
onError: (e) => error = e,
|
||||||
locale: event.locale,
|
locale: event.locale,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
bool isLastPage = false;
|
||||||
|
if (data?.data != null && data!.data!.length < pageSize) {
|
||||||
|
isLastPage = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (event.nextPage != null) {
|
if (event.nextPage != null) {
|
||||||
data?.data?.insertAll(0, state.data?.data ?? []);
|
data?.data?.insertAll(0, state.data?.data ?? []);
|
||||||
}
|
}
|
||||||
@ -36,10 +44,13 @@ class HomeBloc extends Bloc<HomeEvent, HomeState> {
|
|||||||
isPaginationLoading: false,
|
isPaginationLoading: false,
|
||||||
data: data,
|
data: data,
|
||||||
error: error,
|
error: error,
|
||||||
|
isAllPagesLoaded: isLastPage,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _onLoadFavouritesData(HomeLoadFavouritesDataEvent event, Emitter<HomeState> emit) async {
|
Future<void> _onLoadFavouritesData(HomeLoadFavouritesDataEvent event, Emitter<HomeState> emit) async {
|
||||||
|
const int pageSize = 10;
|
||||||
|
|
||||||
if (event.nextPage == null) {
|
if (event.nextPage == null) {
|
||||||
emit(state.copyWith(isLoading: true));
|
emit(state.copyWith(isLoading: true));
|
||||||
} else {
|
} else {
|
||||||
@ -51,10 +62,16 @@ class HomeBloc extends Bloc<HomeEvent, HomeState> {
|
|||||||
final data = await repo.loadDataWithIds(
|
final data = await repo.loadDataWithIds(
|
||||||
ids: event.ids ?? [],
|
ids: event.ids ?? [],
|
||||||
page: event.nextPage ?? 1,
|
page: event.nextPage ?? 1,
|
||||||
|
pageSize: pageSize,
|
||||||
onError: (e) => error = e,
|
onError: (e) => error = e,
|
||||||
locale: event.locale,
|
locale: event.locale,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
bool isLastPage = false;
|
||||||
|
if (data?.data != null && data!.data!.length < pageSize) {
|
||||||
|
isLastPage = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (event.nextPage != null) {
|
if (event.nextPage != null) {
|
||||||
data?.data?.insertAll(0, state.data?.data ?? []);
|
data?.data?.insertAll(0, state.data?.data ?? []);
|
||||||
}
|
}
|
||||||
@ -64,6 +81,7 @@ class HomeBloc extends Bloc<HomeEvent, HomeState> {
|
|||||||
isPaginationLoading: false,
|
isPaginationLoading: false,
|
||||||
data: data,
|
data: data,
|
||||||
error: error,
|
error: error,
|
||||||
|
isAllPagesLoaded: isLastPage,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,12 +6,14 @@ class HomeState extends Equatable {
|
|||||||
final bool isLoading;
|
final bool isLoading;
|
||||||
final bool isPaginationLoading;
|
final bool isPaginationLoading;
|
||||||
final String? error;
|
final String? error;
|
||||||
|
final bool isAllPagesLoaded;
|
||||||
|
|
||||||
const HomeState({
|
const HomeState({
|
||||||
this.data,
|
this.data,
|
||||||
this.isLoading = false,
|
this.isLoading = false,
|
||||||
this.isPaginationLoading = false,
|
this.isPaginationLoading = false,
|
||||||
this.error,
|
this.error,
|
||||||
|
this.isAllPagesLoaded = false,
|
||||||
});
|
});
|
||||||
|
|
||||||
HomeState copyWith({
|
HomeState copyWith({
|
||||||
@ -19,11 +21,13 @@ class HomeState extends Equatable {
|
|||||||
bool? isLoading,
|
bool? isLoading,
|
||||||
bool? isPaginationLoading,
|
bool? isPaginationLoading,
|
||||||
String? error,
|
String? error,
|
||||||
|
bool? isAllPagesLoaded,
|
||||||
}) => HomeState(
|
}) => HomeState(
|
||||||
data: data ?? this.data,
|
data: data ?? this.data,
|
||||||
isLoading: isLoading ?? this.isLoading,
|
isLoading: isLoading ?? this.isLoading,
|
||||||
isPaginationLoading: isPaginationLoading ?? this.isPaginationLoading,
|
isPaginationLoading: isPaginationLoading ?? this.isPaginationLoading,
|
||||||
error: error ?? this.error,
|
error: error ?? this.error,
|
||||||
|
isAllPagesLoaded: isAllPagesLoaded ?? this.isAllPagesLoaded,
|
||||||
);
|
);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -32,5 +36,6 @@ class HomeState extends Equatable {
|
|||||||
isLoading,
|
isLoading,
|
||||||
isPaginationLoading,
|
isPaginationLoading,
|
||||||
error,
|
error,
|
||||||
|
isAllPagesLoaded,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -54,7 +54,7 @@ class CardCrypto extends StatelessWidget {
|
|||||||
borderRadius: BorderRadius.circular(15),
|
borderRadius: BorderRadius.circular(15),
|
||||||
boxShadow: [
|
boxShadow: [
|
||||||
BoxShadow(
|
BoxShadow(
|
||||||
color: Colors.grey.withOpacity(0.5),
|
color: Colors.black38.withOpacity(0.2),
|
||||||
spreadRadius: 4,
|
spreadRadius: 4,
|
||||||
offset: const Offset(0, 5),
|
offset: const Offset(0, 5),
|
||||||
blurRadius: 6,
|
blurRadius: 6,
|
||||||
@ -81,43 +81,52 @@ class CardCrypto extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Flexible(
|
Expanded(
|
||||||
child: Padding(
|
child: Column(
|
||||||
padding: const EdgeInsets.only(left: 12.0, top: 12, bottom: 12),
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
child: Column(
|
children: [
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
Expanded(
|
||||||
children: [
|
child: Padding(
|
||||||
Text(
|
padding: const EdgeInsets.only(left: 16, top: 8),
|
||||||
title,
|
child: Column(
|
||||||
style: Theme.of(context).textTheme.headlineLarge,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
),
|
children: [
|
||||||
Text(
|
Text(
|
||||||
currentPrice,
|
title,
|
||||||
style: Theme.of(context).textTheme.bodyLarge),
|
style: Theme.of(context).textTheme.headlineLarge,
|
||||||
],
|
),
|
||||||
),
|
Text(
|
||||||
),
|
currentPrice,
|
||||||
),
|
style: Theme.of(context).textTheme.bodyLarge),
|
||||||
Align(
|
],
|
||||||
alignment: Alignment.bottomRight,
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.fromLTRB(8, 0, 16, 16),
|
|
||||||
child: GestureDetector(
|
|
||||||
onTap: () => onLike?.call(id, title, isLiked),
|
|
||||||
child: AnimatedSwitcher(
|
|
||||||
duration: const Duration(milliseconds: 100),
|
|
||||||
child: isLiked
|
|
||||||
? const Icon(
|
|
||||||
Icons.star,
|
|
||||||
color: Colors.orangeAccent,
|
|
||||||
key: ValueKey(0),
|
|
||||||
)
|
|
||||||
: const Icon(
|
|
||||||
Icons.star_border,
|
|
||||||
key: ValueKey(1),
|
|
||||||
),
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
Row(
|
||||||
|
children: [
|
||||||
|
const Spacer(),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.fromLTRB(8, 0, 16, 16),
|
||||||
|
child: GestureDetector(
|
||||||
|
onTap: () => onLike?.call(id, title, isLiked),
|
||||||
|
child: AnimatedSwitcher(
|
||||||
|
duration: const Duration(milliseconds: 100),
|
||||||
|
child: isLiked
|
||||||
|
? const Icon(
|
||||||
|
Icons.star,
|
||||||
|
color: Colors.orangeAccent,
|
||||||
|
key: ValueKey(0),
|
||||||
|
)
|
||||||
|
: const Icon(
|
||||||
|
Icons.star_border,
|
||||||
|
key: ValueKey(1),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@ -52,7 +52,10 @@ class _CardsListState extends State<CardsList> {
|
|||||||
style: Theme.of(context).textTheme.headlineSmall?.copyWith(color: Colors.red),
|
style: Theme.of(context).textTheme.headlineSmall?.copyWith(color: Colors.red),
|
||||||
)
|
)
|
||||||
: state.isLoading
|
: state.isLoading
|
||||||
? const CircularProgressIndicator()
|
? const Center(child: Padding(
|
||||||
|
padding: EdgeInsets.only(top: 20),
|
||||||
|
child: CircularProgressIndicator(),
|
||||||
|
))
|
||||||
: BlocBuilder<FavouritesBloc, FavouritesState>(
|
: BlocBuilder<FavouritesBloc, FavouritesState>(
|
||||||
builder: (context, likeState) => Expanded(
|
builder: (context, likeState) => Expanded(
|
||||||
child: RefreshIndicator(
|
child: RefreshIndicator(
|
||||||
|
@ -16,7 +16,14 @@ import '../favourites_bloc/favourites_events.dart';
|
|||||||
import '../settings_page/settings_page.dart';
|
import '../settings_page/settings_page.dart';
|
||||||
|
|
||||||
class MainScaffold extends StatefulWidget {
|
class MainScaffold extends StatefulWidget {
|
||||||
const MainScaffold({super.key});
|
const MainScaffold({
|
||||||
|
super.key,
|
||||||
|
this.toggleDarkMode,
|
||||||
|
required this.isDarkModeSelected,
|
||||||
|
});
|
||||||
|
|
||||||
|
final void Function()? toggleDarkMode;
|
||||||
|
final bool isDarkModeSelected;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<MainScaffold> createState() => _MainScaffoldState();
|
State<MainScaffold> createState() => _MainScaffoldState();
|
||||||
@ -30,15 +37,19 @@ class _MainScaffoldState extends State<MainScaffold> {
|
|||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
|
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
|
||||||
title: Text(context.locale.mainAppBarTitle),
|
title: [
|
||||||
|
Text(context.locale.mainAppBarTitle),
|
||||||
|
Text(context.locale.favouritesPageAppBarTitle),
|
||||||
|
Text(context.locale.settingsPageAppBarTitle),
|
||||||
|
][currentPageIndex],
|
||||||
actions: [
|
actions: [
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.only(right: 12.0),
|
padding: const EdgeInsets.only(right: 12.0),
|
||||||
child: IconButton(
|
child: IconButton(
|
||||||
icon: const Icon(Icons.settings),
|
isSelected: widget.isDarkModeSelected,
|
||||||
onPressed: () => Navigator.push(context, MaterialPageRoute<void>(
|
onPressed: () => widget.toggleDarkMode?.call(),
|
||||||
builder: (BuildContext context) => const SettingsPage(),
|
icon: const Icon(Icons.wb_sunny_outlined),
|
||||||
)),
|
selectedIcon: const Icon(Icons.brightness_2_outlined),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -73,7 +84,6 @@ class HomePage extends StatefulWidget {
|
|||||||
class _HomePageState extends State<HomePage> {
|
class _HomePageState extends State<HomePage> {
|
||||||
final TextEditingController searchController = TextEditingController();
|
final TextEditingController searchController = TextEditingController();
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
SvgObjects.init();
|
SvgObjects.init();
|
||||||
@ -86,41 +96,43 @@ class _HomePageState extends State<HomePage> {
|
|||||||
super.initState();
|
super.initState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
searchController.dispose();
|
||||||
|
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: EdgeInsets.only(top: MediaQuery.of(context).padding.top),
|
padding: EdgeInsets.only(top: MediaQuery.of(context).padding.top),
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
Row(
|
Padding(
|
||||||
children: [
|
padding: const EdgeInsets.all(12),
|
||||||
Expanded(
|
child: SearchBar(
|
||||||
flex: 4,
|
controller: searchController,
|
||||||
child: Padding(
|
onChanged: (search) {
|
||||||
padding: const EdgeInsets.all(12),
|
Debounce.run(() => context.read<HomeBloc>().add(HomeLoadDataEvent(search: search, locale: context.locale)));
|
||||||
child: SearchBar(
|
},
|
||||||
controller: searchController,
|
leading: const Icon(Icons.search),
|
||||||
onChanged: (search) {
|
trailing: [
|
||||||
Debounce.run(() => context.read<HomeBloc>().add(HomeLoadDataEvent(search: search, locale: context.locale)));
|
IconButton(
|
||||||
},
|
icon: const Icon(Icons.close),
|
||||||
leading: const Icon(Icons.search),
|
onPressed: () {
|
||||||
trailing: [
|
if (searchController.text.isNotEmpty) {
|
||||||
IconButton(
|
searchController.clear();
|
||||||
icon: const Icon(Icons.close),
|
context.read<HomeBloc>().add(HomeLoadDataEvent(locale: context.locale));
|
||||||
onPressed: () {
|
}
|
||||||
searchController.clear();
|
},
|
||||||
context.read<HomeBloc>().add(HomeLoadDataEvent(locale: context.locale));
|
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
hintText: context.locale.searchHint,
|
|
||||||
elevation: const WidgetStatePropertyAll(0.0),
|
|
||||||
padding: const WidgetStatePropertyAll(EdgeInsets.only(left: 18, right: 10)),
|
|
||||||
backgroundColor: WidgetStatePropertyAll(Theme.of(context).colorScheme.secondaryContainer),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
],
|
||||||
],
|
hintText: context.locale.searchHint,
|
||||||
|
elevation: const WidgetStatePropertyAll(0.0),
|
||||||
|
padding: const WidgetStatePropertyAll(EdgeInsets.only(left: 18, right: 10)),
|
||||||
|
backgroundColor: WidgetStatePropertyAll(Theme.of(context).colorScheme.secondaryContainer),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
CardsList(
|
CardsList(
|
||||||
onListRefresh: _onRefresh,
|
onListRefresh: _onRefresh,
|
||||||
@ -130,7 +142,10 @@ class _HomePageState extends State<HomePage> {
|
|||||||
),
|
),
|
||||||
BlocBuilder<HomeBloc, HomeState>(
|
BlocBuilder<HomeBloc, HomeState>(
|
||||||
builder: (context, state) => state.isPaginationLoading
|
builder: (context, state) => state.isPaginationLoading
|
||||||
? const CircularProgressIndicator()
|
? const Padding(
|
||||||
|
padding: EdgeInsets.all(12),
|
||||||
|
child: CircularProgressIndicator(),
|
||||||
|
)
|
||||||
: const SizedBox.shrink(),
|
: const SizedBox.shrink(),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -138,13 +153,6 @@ class _HomePageState extends State<HomePage> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
void dispose() {
|
|
||||||
searchController.dispose();
|
|
||||||
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
void _showSnackBar(BuildContext context, String title, bool isLiked) {
|
void _showSnackBar(BuildContext context, String title, bool isLiked) {
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
|
||||||
@ -178,7 +186,7 @@ class _HomePageState extends State<HomePage> {
|
|||||||
|
|
||||||
void _onNextPage() {
|
void _onNextPage() {
|
||||||
final bloc = context.read<HomeBloc>();
|
final bloc = context.read<HomeBloc>();
|
||||||
if (!bloc.state.isPaginationLoading) {
|
if (!bloc.state.isPaginationLoading && !bloc.state.isAllPagesLoaded) {
|
||||||
bloc.add(HomeLoadDataEvent(
|
bloc.add(HomeLoadDataEvent(
|
||||||
search: searchController.text,
|
search: searchController.text,
|
||||||
nextPage: bloc.state.data?.nextPage,
|
nextPage: bloc.state.data?.nextPage,
|
||||||
|
@ -12,41 +12,35 @@ class SettingsPage extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Padding(
|
||||||
appBar: AppBar(
|
padding: const EdgeInsets.only(left: 20, right: 16, top: 8),
|
||||||
title: Text(context.locale.settingsPageAppBarTitle),
|
child: Column(
|
||||||
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
|
children: [
|
||||||
),
|
Row(
|
||||||
body: Padding(
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
padding: const EdgeInsets.only(left: 20, right: 16, top: 8),
|
children: [
|
||||||
child: Column(
|
Text(
|
||||||
children: [
|
'${context.locale.settingsLanguage}:',
|
||||||
Row(
|
style: Theme.of(context).textTheme.titleMedium,
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
),
|
||||||
children: [
|
GestureDetector(
|
||||||
Text(
|
onTap: () => context.read<LocaleBloc>().add(const ChangeLocaleEvent()),
|
||||||
'${context.locale.settingsLanguage}:',
|
child: SizedBox.square(
|
||||||
style: Theme.of(context).textTheme.titleMedium,
|
dimension: 50,
|
||||||
),
|
child: Padding(
|
||||||
GestureDetector(
|
padding: const EdgeInsets.only(right: 0),
|
||||||
onTap: () => context.read<LocaleBloc>().add(const ChangeLocaleEvent()),
|
child: BlocBuilder<LocaleBloc, LocaleState>(
|
||||||
child: SizedBox.square(
|
|
||||||
dimension: 50,
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.only(right: 0),
|
|
||||||
child: BlocBuilder<LocaleBloc, LocaleState>(
|
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
return state.currentLocale.languageCode == 'ru'
|
return state.currentLocale.languageCode == 'ru'
|
||||||
? const SvgRu()
|
? const SvgRu()
|
||||||
: const SvgUs();
|
: const SvgUs();
|
||||||
}),
|
}),
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
),
|
||||||
),
|
],
|
||||||
],
|
),
|
||||||
),
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user