Browse Source

Merge pull request #387 from Leptopoda/feature/adaptive-layout

adaptive layout; rework drawer
pull/389/head
Nikolas Rimikis 1 year ago committed by GitHub
parent
commit
c192ae834e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      packages/neon/neon/lib/neon.dart
  2. 278
      packages/neon/neon/lib/src/pages/home.dart
  3. 2
      packages/neon/neon/lib/src/pages/settings.dart
  4. 21
      packages/neon/neon/lib/src/utils/app_implementation.dart
  5. 2
      packages/neon/neon/lib/src/utils/global_options.dart
  6. 1
      packages/neon/neon/lib/src/widgets/app_implementation_icon.dart
  7. 210
      packages/neon/neon/lib/src/widgets/drawer.dart
  8. 137
      packages/neon/neon/lib/src/widgets/drawer_destination.dart
  9. 1
      packages/neon/neon/pubspec.yaml
  10. 3
      packages/neon/neon_files/lib/neon_files.dart
  11. 2
      packages/neon/neon_news/lib/neon_news.dart
  12. 3
      packages/neon/neon_notes/lib/neon_notes.dart
  13. 3
      packages/neon/neon_notifications/lib/neon_notifications.dart
  14. 1
      packages/neon/neon_notifications/lib/pages/main.dart

2
packages/neon/neon/lib/neon.dart

@ -25,6 +25,8 @@ import 'package:neon/src/blocs/blocs.dart';
import 'package:neon/src/models/account.dart'; import 'package:neon/src/models/account.dart';
import 'package:neon/src/models/push_notification.dart'; import 'package:neon/src/models/push_notification.dart';
import 'package:neon/src/router.dart'; import 'package:neon/src/router.dart';
import 'package:neon/src/widgets/drawer.dart';
import 'package:neon/src/widgets/drawer_destination.dart';
import 'package:nextcloud/nextcloud.dart'; import 'package:nextcloud/nextcloud.dart';
import 'package:package_info_plus/package_info_plus.dart'; import 'package:package_info_plus/package_info_plus.dart';
import 'package:path/path.dart' as p; import 'package:path/path.dart' as p;

278
packages/neon/neon/lib/src/pages/home.dart

@ -187,235 +187,11 @@ class _HomePageState extends State<HomePage> {
return const Scaffold(); return const Scaffold();
} }
final isQuickBar = navigationMode == NavigationMode.quickBar; final drawerAlwaysVisible = navigationMode == NavigationMode.drawerAlwaysVisible;
final drawer = Builder(
builder: (final context) => Drawer(
width: isQuickBar ? kQuickBarWidth : null,
child: Container(
padding: isQuickBar ? const EdgeInsets.all(5) : null,
child: Column(
children: [
Expanded(
child: Scrollbar(
controller: drawerScrollController,
interactive: true,
child: ListView(
controller: drawerScrollController,
// Needed for the drawer header to also render in the statusbar
padding: EdgeInsets.zero,
children: [
Builder(
builder: (final context) {
if (accountsSnapshot.hasData) {
if (isQuickBar) {
return Column(
children: [
if (accounts.length != 1) ...[
for (final account in accounts) ...[
Container(
margin: const EdgeInsets.symmetric(
vertical: 5,
),
child: IconButton(
onPressed: () {
_accountsBloc.setActiveAccount(account);
},
tooltip: account.client.humanReadableID,
icon: IntrinsicHeight(
child: NeonUserAvatar(
account: account,
),
),
),
),
],
Container(
margin: const EdgeInsets.only(
top: 10,
),
child: Divider(
height: 5,
color: Theme.of(context).appBarTheme.foregroundColor,
),
),
],
],
);
}
return DrawerHeader(
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.primary,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
if (capabilities.data != null) ...[
if (capabilities.data!.capabilities.theming?.name != null) ...[
Text(
capabilities.data!.capabilities.theming!.name!,
style: DefaultTextStyle.of(context).style.copyWith(
color: Theme.of(context).appBarTheme.foregroundColor,
),
),
],
if (capabilities.data!.capabilities.theming?.logo != null) ...[
Flexible(
child: NeonCachedUrlImage(
url: capabilities.data!.capabilities.theming!.logo!,
),
),
],
] else ...[
NeonException(
capabilities.error,
onRetry: _capabilitiesBloc.refresh,
),
NeonLinearProgressIndicator(
visible: capabilities.loading,
),
],
if (accounts.length != 1) ...[
DropdownButtonHideUnderline(
child: DropdownButton<String>(
isExpanded: true,
dropdownColor: Theme.of(context).colorScheme.primary,
iconEnabledColor: Theme.of(context).colorScheme.onBackground,
value: _account.id,
items: accounts
.map<DropdownMenuItem<String>>(
(final account) => DropdownMenuItem<String>(
value: account.id,
child: NeonAccountTile(
account: account,
dense: true,
textColor:
Theme.of(context).appBarTheme.foregroundColor,
),
),
)
.toList(),
onChanged: (final id) {
if (id != null) {
_accountsBloc.setActiveAccount(accounts.find(id)!);
}
},
),
),
],
],
),
);
}
return Container();
},
),
NeonException(
appImplementations.error,
onlyIcon: isQuickBar,
onRetry: _appsBloc.refresh,
),
NeonLinearProgressIndicator(
visible: appImplementations.loading,
),
if (appImplementations.data != null) ...[
for (final appImplementation in appImplementations.data!) ...[
StreamBuilder<int>(
stream: appImplementation.getUnreadCounter(_appsBloc) ??
BehaviorSubject<int>.seeded(0),
builder: (final context, final unreadCounterSnapshot) {
final unreadCount = unreadCounterSnapshot.data ?? 0;
if (isQuickBar) {
return IconButton(
onPressed: () async {
await _appsBloc.setActiveApp(appImplementation.id);
},
tooltip: appImplementation.name(context),
icon: NeonAppImplementationIcon(
appImplementation: appImplementation,
unreadCount: unreadCount,
color: Theme.of(context).colorScheme.primary,
),
);
}
return ListTile(
key: Key('app-${appImplementation.id}'),
title: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(appImplementation.name(context)),
if (unreadCount > 0) ...[
Text(
unreadCount.toString(),
style: TextStyle(
color: Theme.of(context).colorScheme.primary,
fontWeight: FontWeight.bold,
fontSize: 14,
),
),
],
],
),
leading: appImplementation.buildIcon(context),
minLeadingWidth: 0,
onTap: () async {
await _appsBloc.setActiveApp(appImplementation.id);
if (!mounted) { const drawer = NeonDrawer();
return;
}
Scaffold.maybeOf(context)?.closeDrawer();
},
);
},
),
],
],
],
),
),
),
if (isQuickBar) ...[
IconButton(
onPressed: () => const SettingsRoute().go(context),
tooltip: AppLocalizations.of(context).settings,
icon: Icon(
Icons.settings,
color: Theme.of(context).appBarTheme.foregroundColor,
),
),
] else ...[
ListTile(
key: const Key('settings'),
title: Text(AppLocalizations.of(context).settings),
leading: const Icon(Icons.settings),
minLeadingWidth: 0,
onTap: () async {
Scaffold.maybeOf(context)?.closeDrawer();
const SettingsRoute().go(context);
},
),
],
],
),
),
),
);
final appBar = AppBar( final appBar = AppBar(
scrolledUnderElevation: navigationMode != NavigationMode.drawer ? 0 : null, automaticallyImplyLeading: !drawerAlwaysVisible,
automaticallyImplyLeading: navigationMode == NavigationMode.drawer,
leadingWidth: isQuickBar ? kQuickBarWidth : null,
leading: isQuickBar
? Container(
padding: const EdgeInsets.all(5),
child: capabilities.data?.capabilities.theming?.logo != null
? NeonCachedUrlImage(
url: capabilities.data!.capabilities.theming!.logo!,
svgColor: Theme.of(context).iconTheme.color,
)
: null,
)
: null,
title: Column( title: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
@ -461,7 +237,8 @@ class _HomePageState extends State<HomePage> {
actions: [ actions: [
if (notificationsAppImplementation.data != null) ...[ if (notificationsAppImplementation.data != null) ...[
StreamBuilder<int>( StreamBuilder<int>(
stream: notificationsAppImplementation.data!.getUnreadCounter(_appsBloc), stream: notificationsAppImplementation.data!
.getUnreadCounter(notificationsAppImplementation.data!.getBloc(account)),
builder: (final context, final unreadCounterSnapshot) { builder: (final context, final unreadCounterSnapshot) {
final unreadCount = unreadCounterSnapshot.data ?? 0; final unreadCount = unreadCounterSnapshot.data ?? 0;
return IconButton( return IconButton(
@ -500,13 +277,7 @@ class _HomePageState extends State<HomePage> {
); );
Widget body = Builder( Widget body = Builder(
builder: (final context) => Row( builder: (final context) => Column(
children: [
if (navigationMode == NavigationMode.quickBar) ...[
drawer,
],
Expanded(
child: Column(
children: [ children: [
if (appImplementations.data != null) ...[ if (appImplementations.data != null) ...[
if (appImplementations.data!.isEmpty) ...[ if (appImplementations.data!.isEmpty) ...[
@ -528,15 +299,29 @@ class _HomePageState extends State<HomePage> {
], ],
], ],
), ),
),
],
),
); );
body = MultiProvider( body = MultiProvider(
providers: _appsBloc.appBlocProviders, providers: _appsBloc.appBlocProviders,
child: Scaffold(
key: _scaffoldKey,
resizeToAvoidBottomInset: false,
drawer: !drawerAlwaysVisible ? drawer : null,
appBar: appBar,
body: body,
),
);
if (drawerAlwaysVisible) {
body = Row(
children: [
drawer,
Expanded(
child: body, child: body,
),
],
); );
}
return WillPopScope( return WillPopScope(
onWillPop: () async { onWillPop: () async {
@ -548,22 +333,7 @@ class _HomePageState extends State<HomePage> {
_scaffoldKey.currentState!.openDrawer(); _scaffoldKey.currentState!.openDrawer();
return false; return false;
}, },
child: Row( child: body,
children: [
if (navigationMode == NavigationMode.drawerAlwaysVisible) ...[
drawer,
],
Expanded(
child: Scaffold(
key: _scaffoldKey,
resizeToAvoidBottomInset: false,
drawer: navigationMode == NavigationMode.drawer ? drawer : null,
appBar: appBar,
body: body,
),
),
],
),
); );
}, },
), ),

2
packages/neon/neon/lib/src/pages/settings.dart

@ -78,7 +78,7 @@ class _SettingsPageState extends State<SettingsPage> {
for (final appImplementation in appImplementations) ...[ for (final appImplementation in appImplementations) ...[
if (appImplementation.options.options.isNotEmpty) ...[ if (appImplementation.options.options.isNotEmpty) ...[
CustomSettingsTile( CustomSettingsTile(
leading: appImplementation.buildIcon(context), leading: appImplementation.buildIcon(),
title: Text(appImplementation.name(context)), title: Text(appImplementation.name(context)),
onTap: () { onTap: () {
NextcloudAppSettingsRoute(appid: appImplementation.id).go(context); NextcloudAppSettingsRoute(appid: appImplementation.id).go(context);

21
packages/neon/neon/lib/src/utils/app_implementation.dart

@ -37,22 +37,35 @@ abstract class AppImplementation<T extends Bloc, R extends NextcloudAppSpecificO
}, },
); );
BehaviorSubject<int>? getUnreadCounter(final AppsBloc appsBloc); BehaviorSubject<int>? getUnreadCounter(final T bloc) => null;
Widget get page; Widget get page;
Widget buildIcon( NeonNavigationDestination destination(final BuildContext context) {
final BuildContext context, { final accountsBloc = Provider.of<AccountsBloc>(context, listen: false);
final account = accountsBloc.activeAccount.value!;
final bloc = getBloc(account);
return NeonNavigationDestination(
label: name(context),
icon: buildIcon,
notificationCount: getUnreadCounter(bloc),
);
}
Widget buildIcon({
final Size size = const Size.square(32), final Size size = const Size.square(32),
final Color? color, final Color? color,
}) => }) =>
SizedBox.fromSize( Builder(
builder: (final context) => SizedBox.fromSize(
size: size, size: size,
child: SvgPicture.asset( child: SvgPicture.asset(
'assets/app.svg', 'assets/app.svg',
package: 'neon_$id', package: 'neon_$id',
colorFilter: ColorFilter.mode(color ?? Theme.of(context).colorScheme.primary, BlendMode.srcIn), colorFilter: ColorFilter.mode(color ?? Theme.of(context).colorScheme.primary, BlendMode.srcIn),
), ),
),
); );
void dispose() { void dispose() {

2
packages/neon/neon/lib/src/utils/global_options.dart

@ -224,6 +224,7 @@ class GlobalOptions {
NavigationMode.drawerAlwaysVisible: (final context) => NavigationMode.drawerAlwaysVisible: (final context) =>
AppLocalizations.of(context).globalOptionsNavigationModeDrawerAlwaysVisible, AppLocalizations.of(context).globalOptionsNavigationModeDrawerAlwaysVisible,
}, },
// ignore: deprecated_member_use_from_same_package
NavigationMode.quickBar: (final context) => AppLocalizations.of(context).globalOptionsNavigationModeQuickBar, NavigationMode.quickBar: (final context) => AppLocalizations.of(context).globalOptionsNavigationModeQuickBar,
}), }),
); );
@ -232,5 +233,6 @@ class GlobalOptions {
enum NavigationMode { enum NavigationMode {
drawer, drawer,
drawerAlwaysVisible, drawerAlwaysVisible,
@Deprecated("The new design won't use this anymore")
quickBar, quickBar,
} }

1
packages/neon/neon/lib/src/widgets/app_implementation_icon.dart

@ -24,7 +24,6 @@ class NeonAppImplementationIcon extends StatelessWidget {
Container( Container(
margin: const EdgeInsets.all(5), margin: const EdgeInsets.all(5),
child: appImplementation.buildIcon( child: appImplementation.buildIcon(
context,
size: size, size: size,
color: color, color: color,
), ),

210
packages/neon/neon/lib/src/widgets/drawer.dart

@ -0,0 +1,210 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:meta/meta.dart';
import 'package:neon/l10n/localizations.dart';
import 'package:neon/neon.dart';
import 'package:neon/src/router.dart';
import 'package:neon/src/widgets/drawer_destination.dart';
import 'package:provider/provider.dart';
@internal
class NeonDrawer extends StatelessWidget {
const NeonDrawer({
super.key,
});
@override
Widget build(final BuildContext context) {
final accountsBloc = Provider.of<AccountsBloc>(context, listen: false);
final appsBloc = accountsBloc.activeAppsBloc;
return StreamBuilder(
stream: appsBloc.appImplementations,
builder: (final context, final snapshot) {
if (snapshot.data?.data == null) {
return Container();
}
return _NeonDrawer(
apps: snapshot.data!.data!,
);
},
);
}
}
class _NeonDrawer extends StatefulWidget {
const _NeonDrawer({
required this.apps,
});
final Iterable<AppImplementation> apps;
@override
State<_NeonDrawer> createState() => __NeonDrawerState();
}
class __NeonDrawerState extends State<_NeonDrawer> with SingleTickerProviderStateMixin {
late TabController _tabController;
late AccountsBloc _accountsBloc;
late AppsBloc _appsBloc;
late List<AppImplementation> _apps;
int _activeApp = 0;
@override
void initState() {
super.initState();
_accountsBloc = Provider.of<AccountsBloc>(context, listen: false);
_appsBloc = _accountsBloc.activeAppsBloc;
_apps = widget.apps.toList();
_activeApp = _apps.indexWhere((final app) => app.id == _appsBloc.activeAppID.valueOrNull);
_tabController = TabController(
vsync: this,
length: widget.apps.length,
);
}
@override
void dispose() {
_tabController.dispose();
super.dispose();
}
void onAppChange(final int index) {
Scaffold.maybeOf(context)?.closeDrawer();
// selected item is not a registered app like the SettingsPage
if (index >= _apps.length) {
const SettingsRoute().go(context);
return;
}
setState(() {
_activeApp = index;
});
unawaited(_appsBloc.setActiveApp(_apps[index].id));
//context.goNamed(apps[index].routeName);
}
@override
Widget build(final BuildContext context) {
final appDestinations = _apps.map(
(final app) => NavigationDrawerDestinationExtension.fromNeonDestination(
app.destination(context),
),
);
final drawer = NavigationDrawer(
selectedIndex: _activeApp,
onDestinationSelected: onAppChange,
children: [
const NeonDrawerHeader(),
...appDestinations,
NavigationDrawerDestination(
icon: const Icon(Icons.settings),
label: Text(AppLocalizations.of(context).settings),
),
],
);
return drawer;
}
}
@internal
class NeonDrawerHeader extends StatelessWidget {
const NeonDrawerHeader({super.key});
@override
Widget build(final BuildContext context) {
final accountsBloc = Provider.of<AccountsBloc>(context, listen: false);
final capabilitiesBloc = accountsBloc.activeCapabilitiesBloc;
final accountSelecor = StreamBuilder<List<Account>>(
stream: accountsBloc.accounts,
builder: (final context, final accountsSnapshot) {
final accounts = accountsSnapshot.data;
if (accounts == null || accounts.length <= 1) {
return const SizedBox.shrink();
}
final items = accounts.map((final account) {
final child = NeonAccountTile(
account: account,
dense: true,
textColor: Theme.of(context).appBarTheme.foregroundColor,
);
return DropdownMenuItem(
value: account,
child: child,
);
}).toList();
return DropdownButtonHideUnderline(
child: DropdownButton(
isExpanded: true,
dropdownColor: Theme.of(context).colorScheme.primary,
iconEnabledColor: Theme.of(context).colorScheme.onBackground,
value: accountsBloc.activeAccount.value,
items: items,
onChanged: (final account) {
if (account == null) {
return;
}
accountsBloc.setActiveAccount(account);
},
),
);
},
);
return ResultBuilder<Capabilities>(
stream: capabilitiesBloc.capabilities,
builder: (final context, final capabilities) => DrawerHeader(
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.primary,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
if (capabilities.data != null) ...[
if (capabilities.data!.capabilities.theming?.name != null) ...[
Text(
capabilities.data!.capabilities.theming!.name!,
style: DefaultTextStyle.of(context).style.copyWith(
color: Theme.of(context).appBarTheme.foregroundColor,
),
),
],
if (capabilities.data!.capabilities.theming?.logo != null) ...[
Flexible(
child: NeonCachedUrlImage(
url: capabilities.data!.capabilities.theming!.logo!,
),
),
],
] else ...[
NeonException(
capabilities.error,
onRetry: capabilitiesBloc.refresh,
),
NeonLinearProgressIndicator(
visible: capabilities.loading,
),
],
accountSelecor,
],
),
),
);
}
}

137
packages/neon/neon/lib/src/widgets/drawer_destination.dart

@ -0,0 +1,137 @@
import 'package:flutter/material.dart';
import 'package:neon/neon.dart';
import 'package:rxdart/subjects.dart';
typedef DestinationIconBuilder = Widget Function({Size size, Color color});
class NeonNavigationDestination {
const NeonNavigationDestination({
required this.label,
required this.icon,
this.selectedIcon,
this.notificationCount,
});
final String label;
final DestinationIconBuilder icon;
final Widget? selectedIcon;
final BehaviorSubject<int>? notificationCount;
}
extension NavigationDestinationExtension on NavigationDestination {
static NavigationDestination fromNeonDestination(final NeonNavigationDestination neonDestination) =>
NavigationDestination(
label: neonDestination.label,
icon: neonDestination.icon(),
selectedIcon: neonDestination.selectedIcon,
);
}
extension NavigationRailDestinationExtension on NavigationRailDestination {
static NavigationRailDestination fromNeonDestination(final NeonNavigationDestination neonDestination) {
final iconWIdget = StreamBuilder(
stream: neonDestination.notificationCount,
initialData: 0,
builder: (final context, final snapshot) {
final colorScheme = Theme.of(context).colorScheme;
final color = snapshot.data! > 0 ? colorScheme.primary : colorScheme.onBackground;
const size = Size.square(kAvatarSize * 2 / 3);
final icon = Container(
margin: const EdgeInsets.all(5),
child: neonDestination.icon(size: size, color: color),
);
if (snapshot.data! <= 0) {
return icon;
}
final notificationIdicator = Builder(
builder: (final context) {
final style = TextStyle(
color: Theme.of(context).colorScheme.primary,
fontWeight: FontWeight.bold,
);
return Text(
snapshot.data!.toString(),
style: style,
);
},
);
return Stack(
alignment: Alignment.bottomRight,
children: [
icon,
notificationIdicator,
],
);
},
);
return NavigationRailDestination(
label: Text(neonDestination.label),
icon: iconWIdget,
selectedIcon: neonDestination.selectedIcon,
);
}
}
extension NavigationDrawerDestinationExtension on NavigationDrawerDestination {
static NavigationDrawerDestination fromNeonDestination(final NeonNavigationDestination neonDestination) {
final labelWidget = StreamBuilder(
stream: neonDestination.notificationCount,
initialData: 0,
builder: (final context, final snapshot) {
final label = Text(neonDestination.label);
if (snapshot.data! <= 0) {
return label;
}
final notificationIdicator = Padding(
padding: const EdgeInsets.only(left: 12, right: 24),
child: Builder(
builder: (final context) {
final style = TextStyle(
color: Theme.of(context).colorScheme.primary,
fontWeight: FontWeight.bold,
fontSize: 14,
);
return Text(
snapshot.data!.toString(),
style: style,
);
},
),
);
return Expanded(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
label,
notificationIdicator,
],
),
);
},
);
return NavigationDrawerDestination(
label: labelWidget,
icon: neonDestination.icon(),
selectedIcon: neonDestination.selectedIcon,
);
}
}
extension TabExtension on Tab {
static Tab fromNeonDestination(final NeonNavigationDestination neonDestination) => Tab(
text: neonDestination.label,
icon: neonDestination.icon(),
);
}

1
packages/neon/neon/pubspec.yaml

@ -26,6 +26,7 @@ dependencies:
intl: ^0.18.0 intl: ^0.18.0
json_annotation: ^4.8.1 json_annotation: ^4.8.1
material_design_icons_flutter: ^7.0.7296 material_design_icons_flutter: ^7.0.7296
meta: ^1.9.1
nextcloud: nextcloud:
git: git:
url: https://github.com/provokateurin/nextcloud-neon url: https://github.com/provokateurin/nextcloud-neon

3
packages/neon/neon_files/lib/neon_files.dart

@ -63,7 +63,4 @@ class FilesApp extends AppImplementation<FilesBloc, FilesAppSpecificOptions> {
@override @override
Widget get page => const FilesMainPage(); Widget get page => const FilesMainPage();
@override
BehaviorSubject<int>? getUnreadCounter(final AppsBloc appsBloc) => null;
} }

2
packages/neon/neon_news/lib/neon_news.dart

@ -71,5 +71,5 @@ class NewsApp extends AppImplementation<NewsBloc, NewsAppSpecificOptions> {
Widget get page => const NewsMainPage(); Widget get page => const NewsMainPage();
@override @override
BehaviorSubject<int> getUnreadCounter(final AppsBloc appsBloc) => appsBloc.getAppBloc<NewsBloc>(this).unreadCounter; BehaviorSubject<int> getUnreadCounter(final NewsBloc bloc) => bloc.unreadCounter;
} }

3
packages/neon/neon_notes/lib/neon_notes.dart

@ -60,7 +60,4 @@ class NotesApp extends AppImplementation<NotesBloc, NotesAppSpecificOptions> {
@override @override
Widget get page => const NotesMainPage(); Widget get page => const NotesMainPage();
@override
BehaviorSubject<int>? getUnreadCounter(final AppsBloc appsBloc) => null;
} }

3
packages/neon/neon_notifications/lib/neon_notifications.dart

@ -41,6 +41,5 @@ class NotificationsApp extends AppImplementation<NotificationsBloc, Notification
Widget get page => const NotificationsMainPage(); Widget get page => const NotificationsMainPage();
@override @override
BehaviorSubject<int> getUnreadCounter(final AppsBloc appsBloc) => BehaviorSubject<int> getUnreadCounter(final NotificationsBloc bloc) => bloc.unreadCounter;
appsBloc.getAppBloc<NotificationsBloc>(this).unreadCounter;
} }

1
packages/neon/neon_notifications/lib/pages/main.dart

@ -74,7 +74,6 @@ class _NotificationsMainPageState extends State<NotificationsMainPage> {
), ),
leading: app != null leading: app != null
? app.buildIcon( ? app.buildIcon(
context,
size: const Size.square(40), size: const Size.square(40),
) )
: SizedBox.fromSize( : SizedBox.fromSize(

Loading…
Cancel
Save