Compare commits

..

2 Commits

Author SHA1 Message Date
jahongireshonqulov
2750564b08 feat:browse bloc done 2025-10-25 17:54:59 +05:00
jahongireshonqulov
97aae6e108 feat:browse bloc done 2025-10-25 17:54:56 +05:00
16 changed files with 1044 additions and 37 deletions

View File

@@ -1,6 +1,7 @@
abstract class AppLocaleKeys { abstract class AppLocaleKeys {
///Storage keys ///Storage keys
static const String language = 'language'; static const String language = 'language';
static const String browseSearchHistory = 'browse-search-history';
static const String fontBold = "fontBold"; static const String fontBold = "fontBold";
static const String fontMedium = "fontMedium"; static const String fontMedium = "fontMedium";

View File

@@ -13,6 +13,8 @@ import 'package:get_it/get_it.dart' as _i174;
import 'package:injectable/injectable.dart' as _i526; import 'package:injectable/injectable.dart' as _i526;
import '../../feature/basket/presentation/blocs/basket_bloc.dart' as _i728; import '../../feature/basket/presentation/blocs/basket_bloc.dart' as _i728;
import '../../feature/browse/presentation/blocs/browse_bloc/browse_bloc.dart'
as _i991;
import '../../feature/common/presentation/blocs/language_bloc/language_bloc.dart' import '../../feature/common/presentation/blocs/language_bloc/language_bloc.dart'
as _i942; as _i942;
import '../../feature/home/presentation/blocs/home_bloc/home_bloc.dart' import '../../feature/home/presentation/blocs/home_bloc/home_bloc.dart'
@@ -33,9 +35,10 @@ extension GetItInjectableX on _i174.GetIt {
}) { }) {
final gh = _i526.GetItHelper(this, environment, environmentFilter); final gh = _i526.GetItHelper(this, environment, environmentFilter);
gh.factory<_i1007.HomeBloc>(() => _i1007.HomeBloc()); gh.factory<_i1007.HomeBloc>(() => _i1007.HomeBloc());
gh.factory<_i728.BasketBloc>(() => _i728.BasketBloc());
gh.factory<_i991.BrowseBloc>(() => _i991.BrowseBloc());
gh.factory<_i580.MainBloc>(() => _i580.MainBloc()); gh.factory<_i580.MainBloc>(() => _i580.MainBloc());
gh.factory<_i311.SplashBloc>(() => _i311.SplashBloc()); gh.factory<_i311.SplashBloc>(() => _i311.SplashBloc());
gh.factory<_i728.BasketBloc>(() => _i728.BasketBloc());
gh.singleton<_i306.StorageService>(() => _i306.StorageService()); gh.singleton<_i306.StorageService>(() => _i306.StorageService());
gh.singleton<_i152.AppRoutes>(() => _i152.AppRoutes()); gh.singleton<_i152.AppRoutes>(() => _i152.AppRoutes());
gh.factory<_i942.LanguageBloc>( gh.factory<_i942.LanguageBloc>(

View File

@@ -12,6 +12,16 @@ class StorageService {
_sharedPreference.setString(key, value); _sharedPreference.setString(key, value);
} }
void setStringList({required String key, required String value}) {
final oldList = _sharedPreference.getStringList(key);
final newList = oldList?..add(value);
_sharedPreference.setStringList(key, newList ?? []);
}
List<String> getStringList({required String key}) {
return _sharedPreference.getStringList(key) ?? [];
}
String? getString({required String key}) { String? getString({required String key}) {
return _sharedPreference.getString(key); return _sharedPreference.getString(key);
} }

View File

@@ -1,3 +1,10 @@
export 'presentation/pages/browse_page/browse_page.dart'; export 'presentation/pages/browse_page/browse_page.dart';
export 'package:food_delivery_client/feature/browse/presentation/pages/browse_page/widgets/w_browse_body.dart'; export 'package:food_delivery_client/feature/browse/presentation/pages/browse_page/widgets/w_browse_body.dart';
export 'package:food_delivery_client/feature/browse/presentation/pages/browse_page/widgets/w_browse_item.dart'; export 'package:food_delivery_client/feature/browse/presentation/pages/browse_page/widgets/w_browse_item.dart';
export "presentation/blocs/browse_bloc/browse_bloc.dart";
export 'package:food_delivery_client/feature/browse/presentation/pages/browse_page/widgets/w_all_categories_skeletonizer.dart';
export 'package:food_delivery_client/feature/browse/presentation/pages/browse_page/widgets/w_browse_skeletonizer.dart';
export 'package:food_delivery_client/feature/browse/presentation/pages/browse_page/widgets/w_all_categories.dart';
export 'package:food_delivery_client/feature/browse/presentation/pages/browse_page/widgets/w_top_categories.dart';
export 'package:food_delivery_client/feature/common/presentation/widgets/app_text_form_field.dart';
export 'package:food_delivery_client/feature/browse/presentation/pages/browse_page/widgets/w_top_categories_skeletonizer.dart';

View File

@@ -0,0 +1,48 @@
import 'package:food_delivery_client/food_delivery_client.dart';
part 'browse_event.dart';
part 'browse_state.dart';
part 'browse_bloc.freezed.dart';
@injectable
class BrowseBloc extends Bloc<BrowseEvent, BrowseState> {
BrowseBloc() : super(const BrowseState()) {
on<_GetTopCategories>(_onGetTopCategories);
on<_GetAllCategories>(_onGetAllCategories);
on<_GetSearchHistory>(_onGetSearchHistory);
on<_FocusChanged>(_onFocusChanged);
}
Future<void> _onGetTopCategories(
_GetTopCategories event,
Emitter<BrowseState> emit,
) async {
emit(state.copyWith(topCategorySt: RequestStatus.loading));
await Future.delayed(TimeDelayConst.duration3);
emit(state.copyWith(topCategorySt: RequestStatus.loaded));
}
Future<void> _onGetAllCategories(
_GetAllCategories event,
Emitter<BrowseState> emit,
) async {
emit(state.copyWith(allCategorySt: RequestStatus.loading));
await Future.delayed(TimeDelayConst.duration3);
emit(state.copyWith(allCategorySt: RequestStatus.loaded));
}
Future<void> _onGetSearchHistory(
_GetSearchHistory event,
Emitter<BrowseState> emit,
) async {
emit(state.copyWith(searchHistorySt: RequestStatus.loading));
await Future.delayed(TimeDelayConst.duration3);
emit(state.copyWith(searchHistorySt: RequestStatus.loading));
}
void _onFocusChanged(_FocusChanged event, Emitter<BrowseState> emit) {
emit(state.copyWith(isActive: event.isActive ?? !(state.isActive)));
}
}

View File

@@ -0,0 +1,667 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
// coverage:ignore-file
// ignore_for_file: type=lint
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
part of 'browse_bloc.dart';
// **************************************************************************
// FreezedGenerator
// **************************************************************************
// dart format off
T _$identity<T>(T value) => value;
/// @nodoc
mixin _$BrowseEvent {
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is BrowseEvent);
}
@override
int get hashCode => runtimeType.hashCode;
@override
String toString() {
return 'BrowseEvent()';
}
}
/// @nodoc
class $BrowseEventCopyWith<$Res> {
$BrowseEventCopyWith(BrowseEvent _, $Res Function(BrowseEvent) __);
}
/// Adds pattern-matching-related methods to [BrowseEvent].
extension BrowseEventPatterns on BrowseEvent {
/// A variant of `map` that fallback to returning `orElse`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeMap<TResult extends Object?>({TResult Function( _Started value)? started,TResult Function( _GetTopCategories value)? getTopCategories,TResult Function( _GetAllCategories value)? getAllCategories,TResult Function( _GetSearchHistory value)? getSearchHistory,TResult Function( _FocusChanged value)? focusChanged,required TResult orElse(),}){
final _that = this;
switch (_that) {
case _Started() when started != null:
return started(_that);case _GetTopCategories() when getTopCategories != null:
return getTopCategories(_that);case _GetAllCategories() when getAllCategories != null:
return getAllCategories(_that);case _GetSearchHistory() when getSearchHistory != null:
return getSearchHistory(_that);case _FocusChanged() when focusChanged != null:
return focusChanged(_that);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// Callbacks receives the raw object, upcasted.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case final Subclass2 value:
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult map<TResult extends Object?>({required TResult Function( _Started value) started,required TResult Function( _GetTopCategories value) getTopCategories,required TResult Function( _GetAllCategories value) getAllCategories,required TResult Function( _GetSearchHistory value) getSearchHistory,required TResult Function( _FocusChanged value) focusChanged,}){
final _that = this;
switch (_that) {
case _Started():
return started(_that);case _GetTopCategories():
return getTopCategories(_that);case _GetAllCategories():
return getAllCategories(_that);case _GetSearchHistory():
return getSearchHistory(_that);case _FocusChanged():
return focusChanged(_that);case _:
throw StateError('Unexpected subclass');
}
}
/// A variant of `map` that fallback to returning `null`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>({TResult? Function( _Started value)? started,TResult? Function( _GetTopCategories value)? getTopCategories,TResult? Function( _GetAllCategories value)? getAllCategories,TResult? Function( _GetSearchHistory value)? getSearchHistory,TResult? Function( _FocusChanged value)? focusChanged,}){
final _that = this;
switch (_that) {
case _Started() when started != null:
return started(_that);case _GetTopCategories() when getTopCategories != null:
return getTopCategories(_that);case _GetAllCategories() when getAllCategories != null:
return getAllCategories(_that);case _GetSearchHistory() when getSearchHistory != null:
return getSearchHistory(_that);case _FocusChanged() when focusChanged != null:
return focusChanged(_that);case _:
return null;
}
}
/// A variant of `when` that fallback to an `orElse` callback.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>({TResult Function()? started,TResult Function()? getTopCategories,TResult Function()? getAllCategories,TResult Function()? getSearchHistory,TResult Function( bool? isActive)? focusChanged,required TResult orElse(),}) {final _that = this;
switch (_that) {
case _Started() when started != null:
return started();case _GetTopCategories() when getTopCategories != null:
return getTopCategories();case _GetAllCategories() when getAllCategories != null:
return getAllCategories();case _GetSearchHistory() when getSearchHistory != null:
return getSearchHistory();case _FocusChanged() when focusChanged != null:
return focusChanged(_that.isActive);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// As opposed to `map`, this offers destructuring.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case Subclass2(:final field2):
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult when<TResult extends Object?>({required TResult Function() started,required TResult Function() getTopCategories,required TResult Function() getAllCategories,required TResult Function() getSearchHistory,required TResult Function( bool? isActive) focusChanged,}) {final _that = this;
switch (_that) {
case _Started():
return started();case _GetTopCategories():
return getTopCategories();case _GetAllCategories():
return getAllCategories();case _GetSearchHistory():
return getSearchHistory();case _FocusChanged():
return focusChanged(_that.isActive);case _:
throw StateError('Unexpected subclass');
}
}
/// A variant of `when` that fallback to returning `null`
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>({TResult? Function()? started,TResult? Function()? getTopCategories,TResult? Function()? getAllCategories,TResult? Function()? getSearchHistory,TResult? Function( bool? isActive)? focusChanged,}) {final _that = this;
switch (_that) {
case _Started() when started != null:
return started();case _GetTopCategories() when getTopCategories != null:
return getTopCategories();case _GetAllCategories() when getAllCategories != null:
return getAllCategories();case _GetSearchHistory() when getSearchHistory != null:
return getSearchHistory();case _FocusChanged() when focusChanged != null:
return focusChanged(_that.isActive);case _:
return null;
}
}
}
/// @nodoc
class _Started implements BrowseEvent {
const _Started();
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _Started);
}
@override
int get hashCode => runtimeType.hashCode;
@override
String toString() {
return 'BrowseEvent.started()';
}
}
/// @nodoc
class _GetTopCategories implements BrowseEvent {
const _GetTopCategories();
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _GetTopCategories);
}
@override
int get hashCode => runtimeType.hashCode;
@override
String toString() {
return 'BrowseEvent.getTopCategories()';
}
}
/// @nodoc
class _GetAllCategories implements BrowseEvent {
const _GetAllCategories();
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _GetAllCategories);
}
@override
int get hashCode => runtimeType.hashCode;
@override
String toString() {
return 'BrowseEvent.getAllCategories()';
}
}
/// @nodoc
class _GetSearchHistory implements BrowseEvent {
const _GetSearchHistory();
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _GetSearchHistory);
}
@override
int get hashCode => runtimeType.hashCode;
@override
String toString() {
return 'BrowseEvent.getSearchHistory()';
}
}
/// @nodoc
class _FocusChanged implements BrowseEvent {
const _FocusChanged(this.isActive);
final bool? isActive;
/// Create a copy of BrowseEvent
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
_$FocusChangedCopyWith<_FocusChanged> get copyWith => __$FocusChangedCopyWithImpl<_FocusChanged>(this, _$identity);
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _FocusChanged&&(identical(other.isActive, isActive) || other.isActive == isActive));
}
@override
int get hashCode => Object.hash(runtimeType,isActive);
@override
String toString() {
return 'BrowseEvent.focusChanged(isActive: $isActive)';
}
}
/// @nodoc
abstract mixin class _$FocusChangedCopyWith<$Res> implements $BrowseEventCopyWith<$Res> {
factory _$FocusChangedCopyWith(_FocusChanged value, $Res Function(_FocusChanged) _then) = __$FocusChangedCopyWithImpl;
@useResult
$Res call({
bool? isActive
});
}
/// @nodoc
class __$FocusChangedCopyWithImpl<$Res>
implements _$FocusChangedCopyWith<$Res> {
__$FocusChangedCopyWithImpl(this._self, this._then);
final _FocusChanged _self;
final $Res Function(_FocusChanged) _then;
/// Create a copy of BrowseEvent
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') $Res call({Object? isActive = freezed,}) {
return _then(_FocusChanged(
freezed == isActive ? _self.isActive : isActive // ignore: cast_nullable_to_non_nullable
as bool?,
));
}
}
/// @nodoc
mixin _$BrowseState {
RequestStatus get topCategorySt; RequestStatus get allCategorySt; RequestStatus get searchHistorySt; List<String> get searchHistory; bool get isActive;
/// Create a copy of BrowseState
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
$BrowseStateCopyWith<BrowseState> get copyWith => _$BrowseStateCopyWithImpl<BrowseState>(this as BrowseState, _$identity);
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is BrowseState&&(identical(other.topCategorySt, topCategorySt) || other.topCategorySt == topCategorySt)&&(identical(other.allCategorySt, allCategorySt) || other.allCategorySt == allCategorySt)&&(identical(other.searchHistorySt, searchHistorySt) || other.searchHistorySt == searchHistorySt)&&const DeepCollectionEquality().equals(other.searchHistory, searchHistory)&&(identical(other.isActive, isActive) || other.isActive == isActive));
}
@override
int get hashCode => Object.hash(runtimeType,topCategorySt,allCategorySt,searchHistorySt,const DeepCollectionEquality().hash(searchHistory),isActive);
@override
String toString() {
return 'BrowseState(topCategorySt: $topCategorySt, allCategorySt: $allCategorySt, searchHistorySt: $searchHistorySt, searchHistory: $searchHistory, isActive: $isActive)';
}
}
/// @nodoc
abstract mixin class $BrowseStateCopyWith<$Res> {
factory $BrowseStateCopyWith(BrowseState value, $Res Function(BrowseState) _then) = _$BrowseStateCopyWithImpl;
@useResult
$Res call({
RequestStatus topCategorySt, RequestStatus allCategorySt, RequestStatus searchHistorySt, List<String> searchHistory, bool isActive
});
}
/// @nodoc
class _$BrowseStateCopyWithImpl<$Res>
implements $BrowseStateCopyWith<$Res> {
_$BrowseStateCopyWithImpl(this._self, this._then);
final BrowseState _self;
final $Res Function(BrowseState) _then;
/// Create a copy of BrowseState
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') @override $Res call({Object? topCategorySt = null,Object? allCategorySt = null,Object? searchHistorySt = null,Object? searchHistory = null,Object? isActive = null,}) {
return _then(_self.copyWith(
topCategorySt: null == topCategorySt ? _self.topCategorySt : topCategorySt // ignore: cast_nullable_to_non_nullable
as RequestStatus,allCategorySt: null == allCategorySt ? _self.allCategorySt : allCategorySt // ignore: cast_nullable_to_non_nullable
as RequestStatus,searchHistorySt: null == searchHistorySt ? _self.searchHistorySt : searchHistorySt // ignore: cast_nullable_to_non_nullable
as RequestStatus,searchHistory: null == searchHistory ? _self.searchHistory : searchHistory // ignore: cast_nullable_to_non_nullable
as List<String>,isActive: null == isActive ? _self.isActive : isActive // ignore: cast_nullable_to_non_nullable
as bool,
));
}
}
/// Adds pattern-matching-related methods to [BrowseState].
extension BrowseStatePatterns on BrowseState {
/// A variant of `map` that fallback to returning `orElse`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _BrowseState value)? $default,{required TResult orElse(),}){
final _that = this;
switch (_that) {
case _BrowseState() when $default != null:
return $default(_that);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// Callbacks receives the raw object, upcasted.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case final Subclass2 value:
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _BrowseState value) $default,){
final _that = this;
switch (_that) {
case _BrowseState():
return $default(_that);case _:
throw StateError('Unexpected subclass');
}
}
/// A variant of `map` that fallback to returning `null`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _BrowseState value)? $default,){
final _that = this;
switch (_that) {
case _BrowseState() when $default != null:
return $default(_that);case _:
return null;
}
}
/// A variant of `when` that fallback to an `orElse` callback.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( RequestStatus topCategorySt, RequestStatus allCategorySt, RequestStatus searchHistorySt, List<String> searchHistory, bool isActive)? $default,{required TResult orElse(),}) {final _that = this;
switch (_that) {
case _BrowseState() when $default != null:
return $default(_that.topCategorySt,_that.allCategorySt,_that.searchHistorySt,_that.searchHistory,_that.isActive);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// As opposed to `map`, this offers destructuring.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case Subclass2(:final field2):
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( RequestStatus topCategorySt, RequestStatus allCategorySt, RequestStatus searchHistorySt, List<String> searchHistory, bool isActive) $default,) {final _that = this;
switch (_that) {
case _BrowseState():
return $default(_that.topCategorySt,_that.allCategorySt,_that.searchHistorySt,_that.searchHistory,_that.isActive);case _:
throw StateError('Unexpected subclass');
}
}
/// A variant of `when` that fallback to returning `null`
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( RequestStatus topCategorySt, RequestStatus allCategorySt, RequestStatus searchHistorySt, List<String> searchHistory, bool isActive)? $default,) {final _that = this;
switch (_that) {
case _BrowseState() when $default != null:
return $default(_that.topCategorySt,_that.allCategorySt,_that.searchHistorySt,_that.searchHistory,_that.isActive);case _:
return null;
}
}
}
/// @nodoc
class _BrowseState implements BrowseState {
const _BrowseState({this.topCategorySt = RequestStatus.initial, this.allCategorySt = RequestStatus.initial, this.searchHistorySt = RequestStatus.initial, final List<String> searchHistory = const [], this.isActive = false}): _searchHistory = searchHistory;
@override@JsonKey() final RequestStatus topCategorySt;
@override@JsonKey() final RequestStatus allCategorySt;
@override@JsonKey() final RequestStatus searchHistorySt;
final List<String> _searchHistory;
@override@JsonKey() List<String> get searchHistory {
if (_searchHistory is EqualUnmodifiableListView) return _searchHistory;
// ignore: implicit_dynamic_type
return EqualUnmodifiableListView(_searchHistory);
}
@override@JsonKey() final bool isActive;
/// Create a copy of BrowseState
/// with the given fields replaced by the non-null parameter values.
@override @JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
_$BrowseStateCopyWith<_BrowseState> get copyWith => __$BrowseStateCopyWithImpl<_BrowseState>(this, _$identity);
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _BrowseState&&(identical(other.topCategorySt, topCategorySt) || other.topCategorySt == topCategorySt)&&(identical(other.allCategorySt, allCategorySt) || other.allCategorySt == allCategorySt)&&(identical(other.searchHistorySt, searchHistorySt) || other.searchHistorySt == searchHistorySt)&&const DeepCollectionEquality().equals(other._searchHistory, _searchHistory)&&(identical(other.isActive, isActive) || other.isActive == isActive));
}
@override
int get hashCode => Object.hash(runtimeType,topCategorySt,allCategorySt,searchHistorySt,const DeepCollectionEquality().hash(_searchHistory),isActive);
@override
String toString() {
return 'BrowseState(topCategorySt: $topCategorySt, allCategorySt: $allCategorySt, searchHistorySt: $searchHistorySt, searchHistory: $searchHistory, isActive: $isActive)';
}
}
/// @nodoc
abstract mixin class _$BrowseStateCopyWith<$Res> implements $BrowseStateCopyWith<$Res> {
factory _$BrowseStateCopyWith(_BrowseState value, $Res Function(_BrowseState) _then) = __$BrowseStateCopyWithImpl;
@override @useResult
$Res call({
RequestStatus topCategorySt, RequestStatus allCategorySt, RequestStatus searchHistorySt, List<String> searchHistory, bool isActive
});
}
/// @nodoc
class __$BrowseStateCopyWithImpl<$Res>
implements _$BrowseStateCopyWith<$Res> {
__$BrowseStateCopyWithImpl(this._self, this._then);
final _BrowseState _self;
final $Res Function(_BrowseState) _then;
/// Create a copy of BrowseState
/// with the given fields replaced by the non-null parameter values.
@override @pragma('vm:prefer-inline') $Res call({Object? topCategorySt = null,Object? allCategorySt = null,Object? searchHistorySt = null,Object? searchHistory = null,Object? isActive = null,}) {
return _then(_BrowseState(
topCategorySt: null == topCategorySt ? _self.topCategorySt : topCategorySt // ignore: cast_nullable_to_non_nullable
as RequestStatus,allCategorySt: null == allCategorySt ? _self.allCategorySt : allCategorySt // ignore: cast_nullable_to_non_nullable
as RequestStatus,searchHistorySt: null == searchHistorySt ? _self.searchHistorySt : searchHistorySt // ignore: cast_nullable_to_non_nullable
as RequestStatus,searchHistory: null == searchHistory ? _self._searchHistory : searchHistory // ignore: cast_nullable_to_non_nullable
as List<String>,isActive: null == isActive ? _self.isActive : isActive // ignore: cast_nullable_to_non_nullable
as bool,
));
}
}
// dart format on

View File

@@ -0,0 +1,14 @@
part of 'browse_bloc.dart';
@freezed
class BrowseEvent with _$BrowseEvent {
const factory BrowseEvent.started() = _Started;
const factory BrowseEvent.getTopCategories() = _GetTopCategories;
const factory BrowseEvent.getAllCategories() = _GetAllCategories;
const factory BrowseEvent.getSearchHistory() = _GetSearchHistory;
const factory BrowseEvent.focusChanged(bool? isActive) = _FocusChanged;
}

View File

@@ -0,0 +1,12 @@
part of 'browse_bloc.dart';
@freezed
abstract class BrowseState with _$BrowseState {
const factory BrowseState({
@Default(RequestStatus.initial) RequestStatus topCategorySt,
@Default(RequestStatus.initial) RequestStatus allCategorySt,
@Default(RequestStatus.initial) RequestStatus searchHistorySt,
@Default([]) List<String> searchHistory,
@Default(false) bool isActive,
}) = _BrowseState;
}

View File

@@ -6,8 +6,11 @@ class BrowsePage extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return WLayout( return BlocProvider(
child: Scaffold(body:WBrowseBody() ), create: (context) => sl<BrowseBloc>()
..add(BrowseEvent.getTopCategories())
..add(BrowseEvent.getAllCategories()),
child: WLayout(child: Scaffold(body: WBrowseBody())),
); );
} }
} }

View File

@@ -1,8 +1,25 @@
import '../../../../../../food_delivery_client.dart'; import '../../../../../../food_delivery_client.dart';
class WAllCategories extends StatelessWidget { class WAllCategories extends StatelessWidget {
const WAllCategories({super.key}); const WAllCategories({super.key});
@override
Widget build(BuildContext context) {
return BlocBuilder<BrowseBloc, BrowseState>(
builder: (context, state) {
if (state.allCategorySt.isLoaded()) {
return WAllCategoriesBody();
}
return WAllCategoriesSkeletonizer();
},
);
}
}
class WAllCategoriesBody extends StatelessWidget {
const WAllCategoriesBody({super.key});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Column( return Column(

View File

@@ -0,0 +1,41 @@
import '../../../../../../food_delivery_client.dart';
class WAllCategoriesSkeletonizer extends StatelessWidget {
const WAllCategoriesSkeletonizer({
super.key,
});
@override
Widget build(BuildContext context) {
return Skeletonizer(
enabled: true,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
25.verticalSpace,
Text(
context.loc.allCategories,
style: AppTextStyles.size24Medium.copyWith(height: 36 / 24),
),
11.verticalSpace,
GridView.builder(
itemCount: 10,
shrinkWrap: true,
padding: EdgeInsets.zero,
physics: const NeverScrollableScrollPhysics(),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
mainAxisSpacing: 15,
crossAxisSpacing: 10,
mainAxisExtent: 140,
),
itemBuilder: (context, index) {
return WBrowseSkeletonizerItem();
},
),
],
),
);
}
}

View File

@@ -1,14 +1,44 @@
import 'package:food_delivery_client/feature/browse/presentation/pages/browse_page/widgets/w_all_categories.dart';
import 'package:food_delivery_client/feature/browse/presentation/pages/browse_page/widgets/w_top_categories.dart';
import 'package:food_delivery_client/feature/common/presentation/widgets/app_text_form_field.dart';
import '../../../../../../food_delivery_client.dart'; import '../../../../../../food_delivery_client.dart';
class WBrowseBody extends StatelessWidget { class WBrowseBody extends StatefulWidget {
const WBrowseBody({super.key}); const WBrowseBody({super.key});
@override
State<WBrowseBody> createState() => _WBrowseBodyState();
}
class _WBrowseBodyState extends State<WBrowseBody> {
late FocusNode _focusNode;
late TextEditingController _controller;
@override
void initState() {
_controller = TextEditingController();
_focusNode = FocusNode();
_focusNode.addListener(() {
context.read<BrowseBloc>().add(BrowseEvent.focusChanged(true));
});
super.initState();
}
void listener() {
_focusNode.addListener(() {
log("${_focusNode.hasFocus}");
setState(() {});
});
}
@override
void dispose() {
_controller.dispose();
_focusNode.dispose();
super.dispose();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocBuilder<BrowseBloc, BrowseState>(
builder: (context, state) {
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
@@ -18,26 +48,70 @@ class WBrowseBody extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
10.verticalSpace, 10.verticalSpace,
AppTextFormField( Row(
controller: TextEditingController(), spacing: 15,
children: [
/*
InkWell(
onTap: () {},
borderRadius: AppUtils.kBorderRadius25,
child: Ink(
height: 44,
width: 44,
decoration: BoxDecoration(
color: AppColors.cEEEEEE,
borderRadius: AppUtils.kBorderRadius25,
),
child: SizedBox(
height: 44,
width: 44,
child: SvgPicture.asset(
AppIcons.icBack,
height: 20,
width: 20,
).paddingAll(10),
),
),
),
*/
Expanded(
child: AppTextFormField(
focusNode: _focusNode,
controller: _controller,
prefixIcon: SvgPicture.asset(AppIcons.icSearch), prefixIcon: SvgPicture.asset(AppIcons.icSearch),
hintText: context.loc.categoriesShort, hintText: context.loc.categoriesShort,
hintTextStyle: AppTextStyles.size16Medium.copyWith( hintTextStyle: AppTextStyles.size16Medium.copyWith(
color: AppColors.c660000 color: AppColors.c660000,
), ),
), ),
),
],
),
15.verticalSpace, 15.verticalSpace,
], ],
), ),
), ),
Expanded( Expanded(
child: RefreshIndicator.adaptive(
onRefresh: () async {
context.read<BrowseBloc>()
..add(BrowseEvent.getTopCategories())
..add(BrowseEvent.getAllCategories());
},
child: SingleChildScrollView( child: SingleChildScrollView(
child: Column( child: Column(
children: [WTopCategories(), WAllCategories(), 40.verticalSpace], children: [
WTopCategories(),
WAllCategories(),
40.verticalSpace,
],
),
), ),
), ),
), ),
], ],
);
},
).paddingSymmetric(horizontal: 16); ).paddingSymmetric(horizontal: 16);
} }
} }

View File

@@ -0,0 +1,52 @@
import '../../../../../../food_delivery_client.dart';
class WBrowseSkeletonizerItem extends StatelessWidget {
const WBrowseSkeletonizerItem({
super.key,
});
@override
Widget build(BuildContext context) {
return Bounceable(
onTap: () {},
child: Ink(
decoration: BoxDecoration(
color: AppColors.cFFFFFF,
borderRadius: AppUtils.kBorderRadius15,
),
child: Column(
children: [
ClipRRect(
borderRadius: AppUtils.kBorderRadiusTop15,
child: CachedNetworkImage(
imageUrl: AppLocaleKeys.foodImageUrl,
width: context.w,
height: 96,
fit: BoxFit.cover,
),
),
SizedBox(
width: context.w,
child: DecoratedBox(
decoration: BoxDecoration(
borderRadius: AppUtils.kBorderRadiusBottom15,
border: Border.all(
color: AppColors.cE8E8E8,
width: 1,
),
),
child: Text(
"Restaurant Rewards",
textAlign: TextAlign.center,
style: AppTextStyles.size16Regular.copyWith(
height: 20 / 16,
),
).paddingSymmetric(horizontal: 30),
),
),
],
),
),
);
}
}

View File

@@ -4,6 +4,22 @@ import '../../../../../../food_delivery_client.dart';
class WTopCategories extends StatelessWidget { class WTopCategories extends StatelessWidget {
const WTopCategories({super.key}); const WTopCategories({super.key});
@override
Widget build(BuildContext context) {
return BlocBuilder<BrowseBloc, BrowseState>(
builder: (context, state) {
if (state.topCategorySt.isLoaded()) {
return WTopCategoriesBody();
}
return WTopCategoriesSkeletonizer();
},
);
}
}
class WTopCategoriesBody extends StatelessWidget {
const WTopCategoriesBody({super.key});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Column( return Column(
@@ -15,7 +31,7 @@ class WTopCategories extends StatelessWidget {
), ),
11.verticalSpace, 11.verticalSpace,
GridView.builder( GridView.builder(
itemCount:6, itemCount: 6,
shrinkWrap: true, shrinkWrap: true,
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
physics: const NeverScrollableScrollPhysics(), physics: const NeverScrollableScrollPhysics(),

View File

@@ -0,0 +1,40 @@
import '../../../../../../food_delivery_client.dart';
class WTopCategoriesSkeletonizer extends StatelessWidget {
const WTopCategoriesSkeletonizer({super.key});
@override
Widget build(BuildContext context) {
return Skeletonizer(
enabled: true,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
context.loc.topCategories,
style: AppTextStyles.size24Medium.copyWith(height: 36 / 24),
),
11.verticalSpace,
GridView.builder(
itemCount: 6,
shrinkWrap: true,
padding: EdgeInsets.zero,
physics: const NeverScrollableScrollPhysics(),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
mainAxisSpacing: 15,
crossAxisSpacing: 10,
mainAxisExtent: 140,
),
itemBuilder: (context, index) {
return WBrowseSkeletonizerItem();
},
),
],
),
);
}
}

View File

@@ -17,7 +17,7 @@ class AppTextFormField extends StatelessWidget {
this.obscureText = false, this.obscureText = false,
required this.controller, required this.controller,
this.prefixIcon, this.prefixIcon,
this.prefixSvgPath, this.prefixSvgPath, this.focusNode,
}); });
final int? maxLines; final int? maxLines;
@@ -36,6 +36,7 @@ class AppTextFormField extends StatelessWidget {
final TextStyle? hintTextStyle; final TextStyle? hintTextStyle;
late final Widget? prefixIcon; late final Widget? prefixIcon;
final String? prefixSvgPath; final String? prefixSvgPath;
final FocusNode? focusNode;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@@ -45,6 +46,7 @@ class AppTextFormField extends StatelessWidget {
maxLines: maxLines ?? 1, maxLines: maxLines ?? 1,
minLines: minLines ?? 1, minLines: minLines ?? 1,
onChanged: onChanged, onChanged: onChanged,
focusNode: focusNode,
inputFormatters: inputFormatters, inputFormatters: inputFormatters,
keyboardType: keyBoardType, keyboardType: keyBoardType,
style: textStyle ?? AppTextStyles.size16Regular, style: textStyle ?? AppTextStyles.size16Regular,