Для дизайна панели мониторинга, показанного на изображении, я должен отображать различные счетчики, полученные из API. Каждый счетчик будет извлекаться из разных API при просмотре метки.
Моя развитая структура,
DashboardScreen
CustomBottomMenuOptionWidget
(label) -StatelessWidget
MenuCountPage
(label) -StatefulWidget
(to display count, I've taken separateMenuCountScreen
widget with its ownevent
,state
&bloc
as per label)
Когда приложение открывается, все работает нормально. Для каждого отдельного пункта меню я могу получить счетчики для каждого ярлыка. Моя основная проблема заключается в том, что пользователь движется вперед в приложении и создает новое событие, а когда вернется на панель управления, как я могу обновить эти счетчики или просто сказать, как я могу добавить событие в BLoC
из MenuCountScreen
, чтобы получить обновленное значение ?.
Текущая реализация:
dashboard.dart (GridView)
GridView.count(
primary: false,
padding: const EdgeInsets.all(20),
crossAxisSpacing: 20,
mainAxisSpacing: 20,
crossAxisCount: 2,
childAspectRatio: 1.3,
children: <Widget>[
HomeBottomGridMenuItem(
label: kMenuLabelCalendar,
onItemClick: () {
_onTapHomeMenuItem(context, kMenuLabelCalendar);
},
icon: ICON_CALENDAR,
itemCountExist: true,
itemCount: 10,
),
...other menu item
)
HomeBottomGridMenuItem.dart
import 'package:flutter/material.dart';
import 'package:flutter_app/resources/colors.dart';
import 'package:flutter_app/screens/dashboard/menu_count/menu_count.dart';
class HomeBottomGridMenuItem extends StatelessWidget {
final String label;
final String icon;
final Function onItemClick;
final bool itemCountExist;
final int itemCount;
HomeBottomGridMenuItem({
this.label,
this.icon,
this.onItemClick,
this.itemCountExist,
this.itemCount,
});
@override
Widget build(BuildContext context) {
return Stack(
fit: StackFit.expand,
children: <Widget>[
InkWell(
onTap: onItemClick,
splashColor: Colors.black26,
child: Container(
padding: EdgeInsets.symmetric(
horizontal: 16.0,
vertical: 8.0,
),
decoration: BoxDecoration(
border: Border.all(
color: Colors.grey,
),
borderRadius: BorderRadius.all(
Radius.circular(
8.0,
),
),
),
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Image.asset(
icon,
height: 40.0,
width: 40.0,
color: kColorDashboardMenuItemIcon,
),
Text(
label,
textAlign: TextAlign.start,
style: Theme.of(context).textTheme.headline4.copyWith(
fontWeight: FontWeight.w400,
color: kColorDashboardMenuItemLabel,
),
)
],
),
),
),
Positioned(
top: 0,
right: 0,
child: Visibility(
visible: itemCountExist,
child: Container(
padding: EdgeInsets.symmetric(
horizontal: 14.0,
vertical: 5.0,
),
decoration: BoxDecoration(
color: kColorAppPrimaryBlackShade,
borderRadius: BorderRadius.only(
topRight: Radius.circular(
5.0,
),
bottomLeft: Radius.circular(
5.0,
),
),
),
child: MenuCountPage(
label: label,
),
),
),
),
],
);
}
}
MenuCountPage.dart
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'menu_count.dart';
class MenuCountPage extends StatelessWidget {
final String label;
MenuCountPage({
@required this.label,
});
@override
Widget build(BuildContext context) {
return BlocProvider<MenuCountBloc>(
create: (context) {
return MenuCountBloc(context: context);
},
child: MenuCountScreen(
menuLabel: label,
),
);
}
}
MenuCountScreen.dart
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_app/widgets/loader_circular.dart';
import 'menu_count.dart';
class MenuCountScreen extends StatefulWidget {
final String menuLabel;
MenuCountScreen({
@required this.menuLabel,
});
@override
_MenuCountScreenState createState() => _MenuCountScreenState();
}
class _MenuCountScreenState extends State<MenuCountScreen> {
MenuCountBloc _menuCountBloc;
@override
void initState() {
_menuCountBloc = BlocProvider.of<MenuCountBloc>(context);
_menuCountBloc.add(
GetMenuCount(menuLabel: widget.menuLabel),
);
super.initState();
}
@override
Widget build(BuildContext context) {
return Center(
child: BlocBuilder<MenuCountBloc, MenuCountState>(
builder: (context, state) {
if (state is MenuCountSuccess) {
return Text(
'${state.count}',
style: Theme.of(context).textTheme.headline2.copyWith(
color: Colors.white,
),
);
}
if (state is MenuCountFail) {
return Text(
'0',
style: Theme.of(context).textTheme.headline2.copyWith(
color: Colors.white,
),
);
}
return CircularLoader(
size: 25,
strokeWidth: 3,
color: Colors.white60,
);
},
),
);
}
}
MenuCountEvent.dart
import 'package:equatable/equatable.dart';
import 'package:flutter/cupertino.dart';
abstract class MenuCountEvent extends Equatable {
const MenuCountEvent();
}
class GetMenuCount extends MenuCountEvent {
final String menuLabel;
GetMenuCount({@required this.menuLabel});
@override
List<Object> get props => [];
}
MenuCountState.dart
import 'package:equatable/equatable.dart';
import 'package:flutter/cupertino.dart';
abstract class MenuCountState extends Equatable {
const MenuCountState();
@override
List<Object> get props => [];
}
class MenuCountInitial extends MenuCountState {}
class MenuCountLoading extends MenuCountState {}
class MenuCountSuccess extends MenuCountState {
final int count;
MenuCountSuccess({@required this.count});
@override
List<Object> get props => [count];
}
class MenuCountFail extends MenuCountState {}
MenuCountBloc.dart
import 'package:chopper/chopper.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_app/api/api_service.dart';
import 'package:flutter_app/models/dashboard_count_responses/events_count_response.dart';
import 'package:flutter_app/models/dashboard_count_responses/open_ticket_count_response.dart';
import 'package:flutter_app/models/dashboard_count_responses/properties_count_response.dart';
import 'package:flutter_app/resources/strings.dart';
import 'package:flutter_app/utility/sharedpref_helper.dart';
import 'package:provider/provider.dart';
import 'menu_count.dart';
class MenuCountBloc extends Bloc<MenuCountEvent, MenuCountState> {
final BuildContext context;
MenuCountBloc({@required this.context});
@override
MenuCountState get initialState => MenuCountInitial();
@override
Stream<MenuCountState> mapEventToState(MenuCountEvent event) async* {
if (event is GetMenuCount) {
yield MenuCountLoading();
if (event.menuLabel.length > 0) {
yield* _getCountValueByLabel(event.menuLabel);
}
}
}
Stream<MenuCountState> _getCountValueByLabel(String menuLabel) async* {
switch (menuLabel) {
case kMenuLabelOpenTickets:
try {
final String token = await SharedPreferenceHelper.getToken();
final Response<OpenTicketCountResponse> apiResponse =
await Provider.of<ApiService>(context, listen: false)
.getOpenTicketCount(token);
if (apiResponse.isSuccessful) {
yield MenuCountSuccess(count: apiResponse.body.openTickets);
} else {
print('API : Response Failed');
yield MenuCountSuccess(count: 0);
}
} catch (exception) {
print('Exception: ${exception.toString()}');
yield MenuCountSuccess(count: 0);
}
break;
case kMenuLabelProperties:
try {
final String token = await SharedPreferenceHelper.getToken();
final Response<PropertiesCountResponse> apiResponse =
await Provider.of<ApiService>(context, listen: false)
.getPropertiesCount(token);
if (apiResponse.isSuccessful) {
yield MenuCountSuccess(count: apiResponse.body.properties_active);
} else {
print('API : Response Failed');
yield MenuCountSuccess(count: 0);
}
} catch (exception) {
print('Exception: ${exception.toString()}');
yield MenuCountSuccess(count: 0);
}
break;
case kMenuLabelCalendar:
try {
final String token = await SharedPreferenceHelper.getToken();
final Response<EventsCountResponse> apiResponse =
await Provider.of<ApiService>(context, listen: false)
.getEventsCount(token);
if (apiResponse.isSuccessful) {
yield MenuCountSuccess(count: apiResponse.body.events);
} else {
print('API : Response Failed');
yield MenuCountSuccess(count: 0);
}
} catch (exception) {
print('Exception: ${exception.toString()}');
yield MenuCountSuccess(count: 0);
}
break;
case kMenuLabelAllTickets:
try {
final String token = await SharedPreferenceHelper.getToken();
final Response<OpenTicketCountResponse> apiResponse =
await Provider.of<ApiService>(context, listen: false)
.getOpenTicketCount(token);
if (apiResponse.isSuccessful) {
yield MenuCountSuccess(count: apiResponse.body.tickets);
} else {
print('API : Response Failed');
yield MenuCountSuccess(count: 0);
}
} catch (exception) {
print('Exception: ${exception.toString()}');
yield MenuCountSuccess(count: 0);
}
break;
default:
yield MenuCountSuccess(count: 0);
}
}
}
То, что я уже пробовал:
Предоставляется
BLoC
от родителя (из «Панели мониторинга»), и когда пользователь возвращается на панель управления, он попытался добавить событие, чтобы получить обновленное количество. Не сработало. (Если это потому, что у меня другой вызов API на основе метки, и каждый счетчик связан с собственным экземпляром MenuCountBloc - если я ошибаюсь, пожалуйста, очистите меня)Пытался взять значение
bool
и передать егоMenuCountScreen
изDashboard
, и когда пользователь вернется на панель управления, обновите значение этогоbool
, думая, что оно обновится и вызовет событие снова, но не сработало.В дополнение к опробованному варианту 1 возьмите 4 разных
int
параметра, чтобы сохранить 4 разных счетчика как вBLoC
, так и вMenuCountState
. Думал, что он сохранит 4 значения дляBLoC
, которые я предоставил изDashboard
. Но не вышло.Я хотел бы знать, верен ли мой способ реализации и что я пробовал. Также возможное решение для достижения моей задачи, в которой я застрял.
EDITED: образец проекта, который я разместил здесь: GitHub