diff --git a/assets/arrow_down_icon.svg b/assets/arrow_down_icon.svg
new file mode 100644
index 0000000..dde5b84
--- /dev/null
+++ b/assets/arrow_down_icon.svg
@@ -0,0 +1,3 @@
+
diff --git a/lib/src/presentation/l10n/app_en.arb b/lib/src/presentation/l10n/app_en.arb
index 5a5605b..6938dc3 100644
--- a/lib/src/presentation/l10n/app_en.arb
+++ b/lib/src/presentation/l10n/app_en.arb
@@ -48,5 +48,8 @@
"commentHint": "Your comment…",
"publish": "Publish",
"add": "Add",
- "eventPhotosRestriction": "You can attach up to 10 photos 🖼️"
+ "eventPhotosRestriction": "You can attach up to 10 photos 🖼️",
+ "sortBy": "Sort by",
+ "numberOfLikes": "Number of likes",
+ "creationDate": "Creation date"
}
\ No newline at end of file
diff --git a/lib/src/presentation/l10n/app_ru.arb b/lib/src/presentation/l10n/app_ru.arb
index cee3027..5797073 100644
--- a/lib/src/presentation/l10n/app_ru.arb
+++ b/lib/src/presentation/l10n/app_ru.arb
@@ -48,5 +48,8 @@
"commentHint": "Ваш комментарий…",
"publish": "Опубликовать",
"add": "Добавить",
- "eventPhotosRestriction": "Вы можете прикрепить до 10 фото 🖼️"
+ "eventPhotosRestriction": "Вы можете прикрепить до 10 фото 🖼️",
+ "sortBy": "Сортировать по",
+ "numberOfLikes": "Количеству лайков",
+ "creationDate": "Дате создания"
}
\ No newline at end of file
diff --git a/lib/src/presentation/l10n/app_uk.arb b/lib/src/presentation/l10n/app_uk.arb
index 7d42465..381a599 100644
--- a/lib/src/presentation/l10n/app_uk.arb
+++ b/lib/src/presentation/l10n/app_uk.arb
@@ -48,5 +48,8 @@
"commentHint": "Ваш коментар…",
"publish": "Опублікувати",
"add": "Додати",
- "eventPhotosRestriction": "Ви можете прикріпити до 10 фото 🖼️"
+ "eventPhotosRestriction": "Ви можете прикріпити до 10 фото 🖼️",
+ "sortBy": "Сортувати за",
+ "numberOfLikes": "Кількістю лайків",
+ "creationDate": "Датою створення"
}
\ No newline at end of file
diff --git a/lib/src/presentation/l10n/suggestions_localizations.dart b/lib/src/presentation/l10n/suggestions_localizations.dart
index 6262267..cc082e5 100644
--- a/lib/src/presentation/l10n/suggestions_localizations.dart
+++ b/lib/src/presentation/l10n/suggestions_localizations.dart
@@ -4,7 +4,6 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:intl/intl.dart' as intl;
-
import 'package:suggest_a_feature/src/presentation/l10n/suggestions_localizations_en.dart';
import 'package:suggest_a_feature/src/presentation/l10n/suggestions_localizations_ru.dart';
import 'package:suggest_a_feature/src/presentation/l10n/suggestions_localizations_uk.dart';
@@ -402,6 +401,24 @@ abstract class SuggestionsLocalizations {
/// In en, this message translates to:
/// **'You can attach up to 10 photos 🖼️'**
String get eventPhotosRestriction;
+
+ /// No description provided for @sortBy.
+ ///
+ /// In en, this message translates to:
+ /// **'Sort by'**
+ String get sortBy;
+
+ /// No description provided for @numberOfLikes.
+ ///
+ /// In en, this message translates to:
+ /// **'Number of likes'**
+ String get numberOfLikes;
+
+ /// No description provided for @creationDate.
+ ///
+ /// In en, this message translates to:
+ /// **'Creation date'**
+ String get creationDate;
}
class _SuggestionsLocalizationsDelegate
diff --git a/lib/src/presentation/l10n/suggestions_localizations_en.dart b/lib/src/presentation/l10n/suggestions_localizations_en.dart
index b85b2eb..eda0273 100644
--- a/lib/src/presentation/l10n/suggestions_localizations_en.dart
+++ b/lib/src/presentation/l10n/suggestions_localizations_en.dart
@@ -46,10 +46,12 @@ class SuggestionsLocalizationsEn extends SuggestionsLocalizations {
String get delete => 'Delete suggestion';
@override
- String get deletionQuestion => 'Are you sure you want to delete the suggestion?';
+ String get deletionQuestion =>
+ 'Are you sure you want to delete the suggestion?';
@override
- String get deletionPhotoQuestion => 'Are you sure you want to delete this photo?';
+ String get deletionPhotoQuestion =>
+ 'Are you sure you want to delete this photo?';
@override
String get title => 'Briefly describe your suggestion';
@@ -155,4 +157,13 @@ class SuggestionsLocalizationsEn extends SuggestionsLocalizations {
@override
String get eventPhotosRestriction => 'You can attach up to 10 photos 🖼️';
+
+ @override
+ String get sortBy => 'Sort by';
+
+ @override
+ String get numberOfLikes => 'Number of likes';
+
+ @override
+ String get creationDate => 'Creation date';
}
diff --git a/lib/src/presentation/l10n/suggestions_localizations_ru.dart b/lib/src/presentation/l10n/suggestions_localizations_ru.dart
index 3105dc8..5444acd 100644
--- a/lib/src/presentation/l10n/suggestions_localizations_ru.dart
+++ b/lib/src/presentation/l10n/suggestions_localizations_ru.dart
@@ -46,10 +46,12 @@ class SuggestionsLocalizationsRu extends SuggestionsLocalizations {
String get delete => 'Удалить предложение';
@override
- String get deletionQuestion => 'Вы действительно хотите удалить это предложение?';
+ String get deletionQuestion =>
+ 'Вы действительно хотите удалить это предложение?';
@override
- String get deletionPhotoQuestion => 'Вы действительно хотите удалить это фото?';
+ String get deletionPhotoQuestion =>
+ 'Вы действительно хотите удалить это фото?';
@override
String get title => 'Кратко опишите ваше предложение';
@@ -155,4 +157,13 @@ class SuggestionsLocalizationsRu extends SuggestionsLocalizations {
@override
String get eventPhotosRestriction => 'Вы можете прикрепить до 10 фото 🖼️';
+
+ @override
+ String get sortBy => 'Сортировать по';
+
+ @override
+ String get numberOfLikes => 'Количеству лайков';
+
+ @override
+ String get creationDate => 'Дате создания';
}
diff --git a/lib/src/presentation/l10n/suggestions_localizations_uk.dart b/lib/src/presentation/l10n/suggestions_localizations_uk.dart
index 1dc502c..0d859e2 100644
--- a/lib/src/presentation/l10n/suggestions_localizations_uk.dart
+++ b/lib/src/presentation/l10n/suggestions_localizations_uk.dart
@@ -157,4 +157,13 @@ class SuggestionsLocalizationsUk extends SuggestionsLocalizations {
@override
String get eventPhotosRestriction => 'Ви можете прикріпити до 10 фото 🖼️';
+
+ @override
+ String get sortBy => 'Сортувати за';
+
+ @override
+ String get numberOfLikes => 'Кількістю лайків';
+
+ @override
+ String get creationDate => 'Датою створення';
}
diff --git a/lib/src/presentation/pages/suggestions/suggestions_cubit.dart b/lib/src/presentation/pages/suggestions/suggestions_cubit.dart
index ea85bac..8764f48 100644
--- a/lib/src/presentation/pages/suggestions/suggestions_cubit.dart
+++ b/lib/src/presentation/pages/suggestions/suggestions_cubit.dart
@@ -1,4 +1,5 @@
import 'dart:async';
+
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:suggest_a_feature/src/domain/data_interfaces/suggestion_repository.dart';
import 'package:suggest_a_feature/src/domain/entities/suggestion.dart';
@@ -18,7 +19,7 @@ class SuggestionsCubit extends Cubit {
completed: [],
declined: [],
duplicated: [],
- isCreateBottomSheetOpened: false,
+ sortType: SortType.likes,
),
) {
_init();
@@ -40,7 +41,7 @@ class SuggestionsCubit extends Cubit {
}
Future _onNewSuggestions(List suggestions) async {
- suggestions.sort((a, b) => b.upvotesCount.compareTo(a.upvotesCount));
+ suggestions.sort(state.sortType.sortFunction);
emit(
state.newState(
@@ -87,12 +88,47 @@ class SuggestionsCubit extends Cubit {
: _suggestionRepository.upvote(suggestion.id);
}
- void openCreateBottomSheet() =>
- emit(state.newState(isCreateBottomSheetOpened: true));
+ void openCreateBottomSheet() => emit(
+ CreateState(
+ requests: state.requests,
+ inProgress: state.inProgress,
+ completed: state.completed,
+ declined: state.declined,
+ duplicated: state.duplicated,
+ sortType: state.sortType,
+ activeTab: state.activeTab,
+ ),
+ );
- void closeCreateBottomSheet() =>
- emit(state.newState(isCreateBottomSheetOpened: false));
+ void closeBottomSheet() => emit(
+ SuggestionsState(
+ requests: state.requests,
+ inProgress: state.inProgress,
+ completed: state.completed,
+ declined: state.declined,
+ duplicated: state.duplicated,
+ sortType: state.sortType,
+ ),
+ );
void changeActiveTab(SuggestionStatus activeTab) =>
emit(state.newState(activeTab: activeTab));
+
+ void openSortingBottomSheet() => emit(
+ SortingState(
+ requests: state.requests,
+ inProgress: state.inProgress,
+ completed: state.completed,
+ declined: state.declined,
+ duplicated: state.duplicated,
+ sortType: state.sortType,
+ ),
+ );
+
+ void onSortTypeChanged(SortType sortType) {
+ if (sortType != state.sortType) {
+ emit(state.newState(sortType: sortType));
+ _onNewSuggestions(_suggestionRepository.suggestions);
+ }
+ }
}
diff --git a/lib/src/presentation/pages/suggestions/suggestions_page.dart b/lib/src/presentation/pages/suggestions/suggestions_page.dart
index fafc50e..cb6d603 100644
--- a/lib/src/presentation/pages/suggestions/suggestions_page.dart
+++ b/lib/src/presentation/pages/suggestions/suggestions_page.dart
@@ -12,6 +12,7 @@ import 'package:suggest_a_feature/src/presentation/pages/suggestions/widgets/sug
import 'package:suggest_a_feature/src/presentation/pages/suggestions/widgets/suggestions_tab_bar.dart';
import 'package:suggest_a_feature/src/presentation/pages/theme/suggestions_theme.dart';
import 'package:suggest_a_feature/src/presentation/pages/widgets/appbar_widget.dart';
+import 'package:suggest_a_feature/src/presentation/pages/widgets/bottom_sheets/sorting_bottom_sheet.dart';
import 'package:suggest_a_feature/src/presentation/pages/widgets/fab.dart';
import 'package:suggest_a_feature/src/presentation/utils/assets_strings.dart';
import 'package:suggest_a_feature/src/presentation/utils/context_utils.dart';
@@ -92,9 +93,9 @@ class _SuggestionsPageState extends State {
child: SuggestionsCubitScope(
child: BlocBuilder(
buildWhen: (previous, current) =>
- previous.isCreateBottomSheetOpened !=
- current.isCreateBottomSheetOpened ||
- previous.activeTab != current.activeTab,
+ previous.type != current.type ||
+ previous.activeTab != current.activeTab ||
+ previous.sortType != current.sortType,
builder: (context, state) {
final cubit = context.read();
return Stack(
@@ -126,12 +127,18 @@ class _SuggestionsPageState extends State {
],
),
),
- if (state.isCreateBottomSheetOpened)
+ if (state is CreateState)
_BottomSheet(
onSaveToGallery: widget.onSaveToGallery,
onUploadMultiplePhotos: widget.onUploadMultiplePhotos,
- onCloseBottomSheet: cubit.closeCreateBottomSheet,
+ onCloseBottomSheet: cubit.closeBottomSheet,
),
+ if (state is SortingState)
+ SortingBottomSheet(
+ closeBottomSheet: cubit.closeBottomSheet,
+ value: state.sortType,
+ onChanged: cubit.onSortTypeChanged,
+ )
],
);
},
@@ -198,6 +205,8 @@ class _MainContentState extends State<_MainContent>
userId: widget.userId,
onVote: context.read().vote,
tabController: _tabController,
+ openSortingBottomSheet:
+ context.read().openSortingBottomSheet,
),
],
),
@@ -246,12 +255,14 @@ class _TabBarView extends StatelessWidget {
final OnUploadMultiplePhotosCallback? onUploadMultiplePhotos;
final void Function(SuggestionStatus status, int i) onVote;
final String userId;
+ final VoidCallback openSortingBottomSheet;
const _TabBarView({
required this.tabController,
required this.onGetUserById,
required this.userId,
required this.onVote,
+ required this.openSortingBottomSheet,
this.onSaveToGallery,
this.onUploadMultiplePhotos,
});
@@ -279,6 +290,7 @@ class _TabBarView extends StatelessWidget {
onUploadMultiplePhotos: onUploadMultiplePhotos,
userId: userId,
vote: (i) => onVote(SuggestionStatus.requests, i),
+ openSortingBottomSheet: openSortingBottomSheet,
),
SuggestionList(
status: SuggestionStatus.inProgress,
@@ -289,6 +301,7 @@ class _TabBarView extends StatelessWidget {
onUploadMultiplePhotos: onUploadMultiplePhotos,
userId: userId,
vote: (i) => onVote(SuggestionStatus.inProgress, i),
+ openSortingBottomSheet: openSortingBottomSheet,
),
SuggestionList(
status: SuggestionStatus.completed,
@@ -299,6 +312,7 @@ class _TabBarView extends StatelessWidget {
onUploadMultiplePhotos: onUploadMultiplePhotos,
userId: userId,
vote: (i) => onVote(SuggestionStatus.completed, i),
+ openSortingBottomSheet: openSortingBottomSheet,
),
SuggestionList(
status: SuggestionStatus.declined,
@@ -309,6 +323,7 @@ class _TabBarView extends StatelessWidget {
onUploadMultiplePhotos: onUploadMultiplePhotos,
userId: userId,
vote: (i) => onVote(SuggestionStatus.declined, i),
+ openSortingBottomSheet: openSortingBottomSheet,
),
SuggestionList(
status: SuggestionStatus.duplicated,
@@ -319,6 +334,7 @@ class _TabBarView extends StatelessWidget {
onUploadMultiplePhotos: onUploadMultiplePhotos,
userId: userId,
vote: (i) => onVote(SuggestionStatus.duplicated, i),
+ openSortingBottomSheet: openSortingBottomSheet,
),
],
),
diff --git a/lib/src/presentation/pages/suggestions/suggestions_state.dart b/lib/src/presentation/pages/suggestions/suggestions_state.dart
index 0d4c2d2..62c6905 100644
--- a/lib/src/presentation/pages/suggestions/suggestions_state.dart
+++ b/lib/src/presentation/pages/suggestions/suggestions_state.dart
@@ -8,7 +8,7 @@ class SuggestionsState extends Equatable {
final List declined;
final List duplicated;
final SuggestionStatus activeTab;
- final bool isCreateBottomSheetOpened;
+ final SortType sortType;
const SuggestionsState({
required this.requests,
@@ -16,7 +16,7 @@ class SuggestionsState extends Equatable {
required this.completed,
required this.declined,
required this.duplicated,
- required this.isCreateBottomSheetOpened,
+ required this.sortType,
this.activeTab = SuggestionStatus.requests,
});
@@ -27,7 +27,7 @@ class SuggestionsState extends Equatable {
List? declined,
List? duplicated,
SuggestionStatus? activeTab,
- bool? isCreateBottomSheetOpened,
+ SortType? sortType,
}) {
return SuggestionsState(
requests: requests ?? this.requests,
@@ -36,8 +36,7 @@ class SuggestionsState extends Equatable {
declined: declined ?? this.declined,
duplicated: duplicated ?? this.duplicated,
activeTab: activeTab ?? this.activeTab,
- isCreateBottomSheetOpened:
- isCreateBottomSheetOpened ?? this.isCreateBottomSheetOpened,
+ sortType: sortType ?? this.sortType,
);
}
@@ -49,6 +48,91 @@ class SuggestionsState extends Equatable {
declined,
duplicated,
activeTab,
- isCreateBottomSheetOpened,
+ sortType,
];
}
+
+class CreateState extends SuggestionsState {
+ const CreateState({
+ required super.requests,
+ required super.inProgress,
+ required super.completed,
+ required super.declined,
+ required super.duplicated,
+ required super.sortType,
+ super.activeTab,
+ });
+
+ @override
+ CreateState newState({
+ List? requests,
+ List? inProgress,
+ List? completed,
+ List? declined,
+ List? duplicated,
+ SuggestionStatus? activeTab,
+ SortType? sortType,
+ }) {
+ return CreateState(
+ requests: requests ?? this.requests,
+ inProgress: inProgress ?? this.inProgress,
+ completed: completed ?? this.completed,
+ declined: declined ?? this.declined,
+ duplicated: duplicated ?? this.duplicated,
+ activeTab: activeTab ?? this.activeTab,
+ sortType: sortType ?? this.sortType,
+ );
+ }
+}
+
+class SortingState extends SuggestionsState {
+ const SortingState({
+ required super.requests,
+ required super.inProgress,
+ required super.completed,
+ required super.declined,
+ required super.duplicated,
+ required super.sortType,
+ super.activeTab,
+ });
+
+ @override
+ SortingState newState({
+ List? requests,
+ List? inProgress,
+ List? completed,
+ List? declined,
+ List? duplicated,
+ SuggestionStatus? activeTab,
+ SortType? sortType,
+ }) {
+ return SortingState(
+ requests: requests ?? this.requests,
+ inProgress: inProgress ?? this.inProgress,
+ completed: completed ?? this.completed,
+ declined: declined ?? this.declined,
+ duplicated: duplicated ?? this.duplicated,
+ activeTab: activeTab ?? this.activeTab,
+ sortType: sortType ?? this.sortType,
+ );
+ }
+}
+
+enum SortType { likes, date }
+
+extension SortTypeExtension on SortType {
+ Comparator get sortFunction {
+ return switch (this) {
+ SortType.likes => (a, b) => b.upvotesCount.compareTo(a.upvotesCount),
+ SortType.date => (a, b) => b.creationTime.compareTo(a.creationTime),
+ };
+ }
+}
+
+extension SuggestionsStateType on SuggestionsState {
+ Type get type {
+ if (this is SortingState) return SortingState;
+ if (this is CreateState) return CreateState;
+ return SuggestionsState;
+ }
+}
diff --git a/lib/src/presentation/pages/suggestions/widgets/list_description.dart b/lib/src/presentation/pages/suggestions/widgets/list_description.dart
index 3c022ec..6b83ed6 100644
--- a/lib/src/presentation/pages/suggestions/widgets/list_description.dart
+++ b/lib/src/presentation/pages/suggestions/widgets/list_description.dart
@@ -1,5 +1,7 @@
import 'package:flutter/material.dart';
+import 'package:flutter_svg/svg.dart';
import 'package:suggest_a_feature/src/presentation/pages/theme/theme_extension.dart';
+import 'package:suggest_a_feature/src/presentation/utils/assets_strings.dart';
import 'package:suggest_a_feature/src/presentation/utils/context_utils.dart';
import 'package:suggest_a_feature/src/presentation/utils/dimensions.dart';
import 'package:suggest_a_feature/suggest_a_feature.dart';
@@ -7,10 +9,12 @@ import 'package:suggest_a_feature/suggest_a_feature.dart';
class ListDescription extends StatelessWidget {
final SuggestionStatus status;
final int length;
+ final VoidCallback openSortingBottomSheet;
const ListDescription({
required this.status,
required this.length,
+ required this.openSortingBottomSheet,
super.key,
});
@@ -59,26 +63,64 @@ class ListDescription extends StatelessWidget {
padding: const EdgeInsets.symmetric(vertical: Dimensions.margin2x),
child: Column(
children: [
- RichText(
- textAlign: TextAlign.center,
- text: TextSpan(
- children: [
- TextSpan(
- text: header,
- style: context.themeData.textTheme.displaySmall,
+ Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ RichText(
+ textAlign: TextAlign.center,
+ text: TextSpan(
+ children: [
+ TextSpan(
+ text: header,
+ style: context.themeData.textTheme.displaySmall,
+ ),
+ TextSpan(
+ text: ' ($length)',
+ style: context.themeData.textTheme.titleMedium,
+ ),
+ ],
),
- TextSpan(
- text: ' ($length)',
- style: context.themeData.textTheme.titleMedium,
+ ),
+ GestureDetector(
+ onTap: openSortingBottomSheet,
+ behavior: HitTestBehavior.translucent,
+ child: Container(
+ padding: const EdgeInsets.symmetric(
+ vertical: 6,
+ horizontal: Dimensions.marginSmall,
+ ),
+ decoration: BoxDecoration(
+ color: theme.secondaryBackgroundColor,
+ borderRadius: const BorderRadius.all(
+ Radius.circular(Dimensions.middleCircularRadius),
+ ),
+ ),
+ child: Row(
+ children: [
+ Text(
+ context.localization.sortBy,
+ style: context.themeData.textTheme.titleMedium
+ ?.copyWith(color: theme.accentColor),
+ ),
+ SvgPicture.asset(
+ AssetStrings.arrowDownIcon,
+ package: AssetStrings.packageName,
+ colorFilter: ColorFilter.mode(
+ theme.accentColor,
+ BlendMode.srcIn,
+ ),
+ ),
+ ],
+ ),
),
- ],
- ),
+ ),
+ ],
),
const SizedBox(height: Dimensions.marginSmall),
Text(
description,
textAlign: TextAlign.center,
- style: context.themeData.textTheme.titleLarge,
+ style: context.themeData.textTheme.titleMedium,
),
],
),
diff --git a/lib/src/presentation/pages/suggestions/widgets/suggestion_list.dart b/lib/src/presentation/pages/suggestions/widgets/suggestion_list.dart
index 6e1b680..4aee662 100644
--- a/lib/src/presentation/pages/suggestions/widgets/suggestion_list.dart
+++ b/lib/src/presentation/pages/suggestions/widgets/suggestion_list.dart
@@ -14,6 +14,7 @@ class SuggestionList extends StatelessWidget {
final OnGetUserById onGetUserById;
final String userId;
final ValueChanged vote;
+ final VoidCallback openSortingBottomSheet;
const SuggestionList({
required this.status,
@@ -22,6 +23,7 @@ class SuggestionList extends StatelessWidget {
required this.onGetUserById,
required this.userId,
required this.vote,
+ required this.openSortingBottomSheet,
this.onUploadMultiplePhotos,
this.onSaveToGallery,
super.key,
@@ -38,7 +40,11 @@ class SuggestionList extends StatelessWidget {
),
itemBuilder: (_, index) {
return index == 0
- ? ListDescription(status: status, length: suggestions.length)
+ ? ListDescription(
+ status: status,
+ length: suggestions.length,
+ openSortingBottomSheet: openSortingBottomSheet,
+ )
: _ListItem(
index: index,
suggestions: suggestions,
diff --git a/lib/src/presentation/pages/widgets/bottom_sheets/label_bottom_sheet.dart b/lib/src/presentation/pages/widgets/bottom_sheets/label_bottom_sheet.dart
index b36d23c..57b7ab4 100644
--- a/lib/src/presentation/pages/widgets/bottom_sheets/label_bottom_sheet.dart
+++ b/lib/src/presentation/pages/widgets/bottom_sheets/label_bottom_sheet.dart
@@ -4,6 +4,7 @@ import 'package:suggest_a_feature/src/presentation/pages/theme/suggestions_theme
import 'package:suggest_a_feature/src/presentation/pages/widgets/bottom_sheets/base_bottom_sheet.dart';
import 'package:suggest_a_feature/src/presentation/pages/widgets/bottom_sheets/bottom_sheet_actions.dart';
import 'package:suggest_a_feature/src/presentation/pages/widgets/suggestions_labels.dart';
+import 'package:suggest_a_feature/src/presentation/pages/widgets/suggestions_radio_button.dart';
import 'package:suggest_a_feature/src/presentation/utils/context_utils.dart';
import 'package:suggest_a_feature/src/presentation/utils/dimensions.dart';
import 'package:wtf_sliding_sheet/wtf_sliding_sheet.dart';
@@ -160,31 +161,9 @@ class _LabelItem extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SuggestionLabels(labels: [label]),
- GestureDetector(
+ SuggestionsRadioButton(
+ selected: selectedLabels.contains(label),
onTap: () => onTap(label),
- child: SizedBox(
- height: Dimensions.defaultSize,
- width: Dimensions.defaultSize,
- child: DecoratedBox(
- decoration: BoxDecoration(
- border: Border.all(
- color: theme.onPrimaryColor,
- width: 0.5,
- ),
- color: selectedLabels.contains(label)
- ? theme.onPrimaryColor
- : theme.thirdBackgroundColor,
- shape: BoxShape.circle,
- ),
- child: selectedLabels.contains(label)
- ? Icon(
- Icons.check,
- size: Dimensions.smallSize,
- color: theme.primaryBackgroundColor,
- )
- : null,
- ),
- ),
),
],
);
diff --git a/lib/src/presentation/pages/widgets/bottom_sheets/sorting_bottom_sheet.dart b/lib/src/presentation/pages/widgets/bottom_sheets/sorting_bottom_sheet.dart
new file mode 100644
index 0000000..dd6fc46
--- /dev/null
+++ b/lib/src/presentation/pages/widgets/bottom_sheets/sorting_bottom_sheet.dart
@@ -0,0 +1,102 @@
+import 'package:flutter/material.dart';
+import 'package:suggest_a_feature/src/presentation/pages/suggestions/suggestions_state.dart';
+import 'package:suggest_a_feature/src/presentation/pages/theme/theme_extension.dart';
+import 'package:suggest_a_feature/src/presentation/pages/widgets/bottom_sheets/base_bottom_sheet.dart';
+import 'package:suggest_a_feature/src/presentation/pages/widgets/suggestions_radio_button.dart';
+import 'package:suggest_a_feature/src/presentation/utils/context_utils.dart';
+import 'package:suggest_a_feature/src/presentation/utils/dimensions.dart';
+import 'package:suggest_a_feature/suggest_a_feature.dart';
+import 'package:wtf_sliding_sheet/wtf_sliding_sheet.dart';
+
+class SortingBottomSheet extends StatefulWidget {
+ final VoidCallback closeBottomSheet;
+ final ValueChanged onChanged;
+ final SortType value;
+
+ const SortingBottomSheet({
+ required this.closeBottomSheet,
+ required this.value,
+ required this.onChanged,
+ super.key,
+ });
+
+ @override
+ State createState() => _SortingBottomSheetState();
+}
+
+class _SortingBottomSheetState extends State {
+ final SheetController _controller = SheetController();
+
+ @override
+ Widget build(BuildContext context) {
+ return BaseBottomSheet(
+ controller: _controller,
+ onClose: ([_]) => _onClose(),
+ backgroundColor: theme.bottomSheetBackgroundColor,
+ previousNavBarColor: theme.primaryBackgroundColor,
+ previousStatusBarColor: theme.primaryBackgroundColor,
+ title: context.localization.sortBy,
+ contentBuilder: (context, _) {
+ return Column(
+ children: [
+ _SortRow(
+ title: context.localization.numberOfLikes,
+ value: SortType.likes,
+ selected: widget.value == SortType.likes,
+ onChanged: widget.onChanged,
+ ),
+ const SizedBox(height: Dimensions.marginSmall),
+ _SortRow(
+ title: context.localization.creationDate,
+ value: SortType.date,
+ onChanged: widget.onChanged,
+ selected: widget.value == SortType.date,
+ ),
+ ],
+ );
+ },
+ );
+ }
+
+ Future _onClose() async {
+ await _controller.collapse();
+ widget.closeBottomSheet();
+ }
+}
+
+class _SortRow extends StatelessWidget {
+ final String title;
+ final SortType value;
+ final ValueChanged onChanged;
+ final bool selected;
+
+ const _SortRow({
+ required this.title,
+ required this.value,
+ required this.onChanged,
+ required this.selected,
+ });
+
+ @override
+ Widget build(BuildContext context) {
+ return Padding(
+ padding: const EdgeInsets.symmetric(
+ vertical: Dimensions.marginSmall,
+ horizontal: Dimensions.marginDefault,
+ ),
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ Text(
+ title,
+ style: context.themeData.textTheme.displaySmall,
+ ),
+ SuggestionsRadioButton(
+ selected: selected,
+ onTap: () => onChanged(value),
+ ),
+ ],
+ ),
+ );
+ }
+}
diff --git a/lib/src/presentation/pages/widgets/suggestions_radio_button.dart b/lib/src/presentation/pages/widgets/suggestions_radio_button.dart
new file mode 100644
index 0000000..8cdddc1
--- /dev/null
+++ b/lib/src/presentation/pages/widgets/suggestions_radio_button.dart
@@ -0,0 +1,41 @@
+import 'package:flutter/material.dart';
+import 'package:suggest_a_feature/src/presentation/utils/dimensions.dart';
+import 'package:suggest_a_feature/suggest_a_feature.dart';
+
+class SuggestionsRadioButton extends StatelessWidget {
+ final bool selected;
+ final VoidCallback onTap;
+ const SuggestionsRadioButton({
+ required this.selected,
+ required this.onTap,
+ super.key,
+ });
+
+ @override
+ Widget build(BuildContext context) {
+ return GestureDetector(
+ onTap: onTap,
+ child: SizedBox(
+ height: Dimensions.defaultSize,
+ width: Dimensions.defaultSize,
+ child: DecoratedBox(
+ decoration: BoxDecoration(
+ border: Border.all(
+ color: theme.onPrimaryColor,
+ width: 0.5,
+ ),
+ color: selected ? theme.onPrimaryColor : theme.thirdBackgroundColor,
+ shape: BoxShape.circle,
+ ),
+ child: selected
+ ? Icon(
+ Icons.check,
+ size: Dimensions.smallSize,
+ color: theme.primaryBackgroundColor,
+ )
+ : null,
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/src/presentation/utils/assets_strings.dart b/lib/src/presentation/utils/assets_strings.dart
index e71ca9a..bea6f50 100644
--- a/lib/src/presentation/utils/assets_strings.dart
+++ b/lib/src/presentation/utils/assets_strings.dart
@@ -1,6 +1,7 @@
class AssetStrings {
static const String packageName = 'suggest_a_feature';
+ static const String arrowDownIcon = 'assets/arrow_down_icon.svg';
static const String addPhotoButton = 'assets/add_photo_icon.svg';
static const String backIconImage = 'assets/arrow_left_icon.svg';
static const String checkIconImage = 'assets/check_icon.svg';
@@ -18,6 +19,7 @@ class AssetStrings {
'assets/suggestions_in_progress.svg';
static const String suggestionsCompleted = 'assets/suggestions_completed.svg';
static const String suggestionsDeclined = 'assets/suggestions_declined.svg';
- static const String suggestionsDuplicated = 'assets/suggestions_duplicated.svg';
+ static const String suggestionsDuplicated =
+ 'assets/suggestions_duplicated.svg';
static const String suggestionsUpvoteArrow = 'assets/arrow_up_suggestion.svg';
}
diff --git a/test/presentation/cubits/suggestions_cubit_test.dart b/test/presentation/cubits/suggestions_cubit_test.dart
index 454a67b..d4186a6 100644
--- a/test/presentation/cubits/suggestions_cubit_test.dart
+++ b/test/presentation/cubits/suggestions_cubit_test.dart
@@ -23,7 +23,7 @@ void main() {
completed: [mockedCompletedSuggestion, mockedCompletedSuggestion2],
declined: const [],
duplicated: const [],
- isCreateBottomSheetOpened: false,
+ sortType: SortType.likes,
);
final mockedSuggestions = [
mockedRequestSuggestion,
@@ -58,8 +58,14 @@ void main() {
seed: () => emptySuggestionsState,
act: (cubit) => cubit.openCreateBottomSheet(),
expect: () => [
- emptySuggestionsState.newState(
- isCreateBottomSheetOpened: true,
+ CreateState(
+ requests: emptySuggestionsState.requests,
+ inProgress: emptySuggestionsState.inProgress,
+ completed: emptySuggestionsState.completed,
+ declined: emptySuggestionsState.declined,
+ duplicated: emptySuggestionsState.duplicated,
+ sortType: emptySuggestionsState.sortType,
+ activeTab: emptySuggestionsState.activeTab,
),
],
);
@@ -74,10 +80,16 @@ void main() {
mockSuggestionRepository,
);
},
- seed: () => emptySuggestionsState.newState(
- isCreateBottomSheetOpened: true,
+ seed: () => CreateState(
+ requests: emptySuggestionsState.requests,
+ inProgress: emptySuggestionsState.inProgress,
+ completed: emptySuggestionsState.completed,
+ declined: emptySuggestionsState.declined,
+ duplicated: emptySuggestionsState.duplicated,
+ sortType: emptySuggestionsState.sortType,
+ activeTab: emptySuggestionsState.activeTab,
),
- act: (cubit) => cubit.closeCreateBottomSheet(),
+ act: (cubit) => cubit.closeBottomSheet(),
expect: () => [
emptySuggestionsState,
],
@@ -132,7 +144,7 @@ void main() {
completed: const [],
declined: const [],
duplicated: const [],
- isCreateBottomSheetOpened: false,
+ sortType: SortType.likes,
),
act: (cubit) {
cubit.vote(SuggestionStatus.requests, 1);
@@ -144,7 +156,7 @@ void main() {
completed: const [],
declined: const [],
duplicated: const [],
- isCreateBottomSheetOpened: false,
+ sortType: SortType.likes,
),
],
);