Browse Source

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

neon: refractor HomePage
pull/364/head
Nikolas Rimikis 1 year ago committed by GitHub
parent
commit
1f94382948
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 722
      packages/neon/neon/lib/src/pages/home.dart

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

@ -183,397 +183,391 @@ class _HomePageState extends State<HomePage> {
) => ) =>
OptionBuilder<NavigationMode>( OptionBuilder<NavigationMode>(
option: _globalOptions.navigationMode, option: _globalOptions.navigationMode,
builder: (final context, final navigationMode) => WillPopScope( builder: (final context, final navigationMode) {
onWillPop: () async { final accounts = accountsSnapshot.data;
if (_scaffoldKey.currentState!.isDrawerOpen) { final account = accounts?.find(_account.id);
Navigator.pop(context); if (accounts == null || account == null) {
return true; return const Scaffold();
} }
_scaffoldKey.currentState!.openDrawer(); final isQuickBar = navigationMode == NavigationMode.quickBar;
return false; final drawer = Builder(
}, builder: (final context) => Drawer(
child: Builder( width: isQuickBar ? kQuickBarWidth : null,
builder: (final context) { child: Container(
if (accountsSnapshot.hasData) { padding: isQuickBar ? const EdgeInsets.all(5) : null,
final accounts = accountsSnapshot.data!; child: Column(
final account = accounts.find(_account.id); children: [
if (account != null) { Expanded(
final isQuickBar = navigationMode == NavigationMode.quickBar; child: Scrollbar(
final drawer = Builder( controller: drawerScrollController,
builder: (final context) => Drawer( interactive: true,
width: isQuickBar ? kQuickBarWidth : null, child: ListView(
child: Container( controller: drawerScrollController,
padding: isQuickBar ? const EdgeInsets.all(5) : null, // Needed for the drawer header to also render in the statusbar
child: Column( padding: EdgeInsets.zero,
children: [ children: [
Expanded( Builder(
child: Scrollbar( builder: (final context) {
controller: drawerScrollController, if (accountsSnapshot.hasData) {
interactive: true, if (isQuickBar) {
child: ListView( return Column(
controller: drawerScrollController, children: [
// Needed for the drawer header to also render in the statusbar if (accounts.length != 1) ...[
padding: EdgeInsets.zero, for (final account in accounts) ...[
children: [ Container(
Builder( margin: const EdgeInsets.symmetric(
builder: (final context) { vertical: 5,
if (accountsSnapshot.hasData) { ),
if (isQuickBar) { child: IconButton(
return Column( onPressed: () {
children: [ _accountsBloc.setActiveAccount(account);
if (accounts.length != 1) ...[ },
for (final account in accounts) ...[ tooltip: account.client.humanReadableID,
Container( icon: IntrinsicHeight(
margin: const EdgeInsets.symmetric( child: NeonAccountAvatar(
vertical: 5, account: account,
),
child: IconButton(
onPressed: () {
_accountsBloc.setActiveAccount(account);
},
tooltip: account.client.humanReadableID,
icon: IntrinsicHeight(
child: NeonAccountAvatar(
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, Container(
mainAxisAlignment: MainAxisAlignment.spaceBetween, margin: const EdgeInsets.only(
children: [ top: 10,
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));
}
},
),
),
],
],
), ),
); child: Divider(
} height: 5,
return Container(); color: Theme.of(context).appBarTheme.foregroundColor,
}, ),
), ),
NeonException( ],
appImplementations.error, ],
onlyIcon: isQuickBar, );
onRetry: _appsBloc.refresh, }
), return DrawerHeader(
NeonLinearProgressIndicator( decoration: BoxDecoration(
visible: appImplementations.loading, color: Theme.of(context).colorScheme.primary,
), ),
if (appImplementations.data != null) ...[ child: Column(
for (final appImplementation in appImplementations.data!) ...[ crossAxisAlignment: CrossAxisAlignment.start,
StreamBuilder<int>( mainAxisAlignment: MainAxisAlignment.spaceBetween,
stream: appImplementation.getUnreadCounter(_appsBloc) ?? children: [
BehaviorSubject<int>.seeded(0), if (capabilities.data != null) ...[
builder: (final context, final unreadCounterSnapshot) { if (capabilities.data!.capabilities.theming?.name != null) ...[
final unreadCount = unreadCounterSnapshot.data ?? 0; Text(
if (isQuickBar) { capabilities.data!.capabilities.theming!.name!,
return IconButton( style: DefaultTextStyle.of(context).style.copyWith(
onPressed: () async { color: Theme.of(context).appBarTheme.foregroundColor,
await _appsBloc.setActiveApp(appImplementation.id); ),
}, ),
tooltip: appImplementation.name(context), ],
icon: NeonAppImplementationIcon( if (capabilities.data!.capabilities.theming?.logo != null) ...[
appImplementation: appImplementation, Flexible(
unreadCount: unreadCount, child: NeonCachedUrlImage(
color: Theme.of(context).colorScheme.primary, url: capabilities.data!.capabilities.theming!.logo!,
), ),
); ),
} ],
return ListTile( ] else ...[
key: Key('app-${appImplementation.id}'), NeonException(
title: Row( capabilities.error,
mainAxisAlignment: MainAxisAlignment.spaceBetween, onRetry: _capabilitiesBloc.refresh,
children: [ ),
Text(appImplementation.name(context)), NeonLinearProgressIndicator(
if (unreadCount > 0) ...[ visible: capabilities.loading,
Text( ),
unreadCount.toString(), ],
style: TextStyle( if (accounts.length != 1) ...[
color: Theme.of(context).colorScheme.primary, DropdownButtonHideUnderline(
fontWeight: FontWeight.bold, child: DropdownButton<String>(
fontSize: 14, 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) {
leading: appImplementation.buildIcon(context), if (id != null) {
minLeadingWidth: 0, _accountsBloc.setActiveAccount(accounts.find(id));
onTap: () async {
await _appsBloc.setActiveApp(appImplementation.id);
if (!mounted) {
return;
} }
Scaffold.maybeOf(context)?.closeDrawer();
}, },
); ),
}, ),
), ],
], ],
], ),
], );
), }
), return Container();
},
), ),
if (isQuickBar) ...[ NeonException(
IconButton( appImplementations.error,
onPressed: () => const SettingsRoute().go(context), onlyIcon: isQuickBar,
tooltip: AppLocalizations.of(context).settings, onRetry: _appsBloc.refresh,
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);
},
),
],
],
),
),
),
);
return Row(
children: [
if (navigationMode == NavigationMode.drawerAlwaysVisible) ...[
drawer,
],
Expanded(
child: Scaffold(
key: _scaffoldKey,
resizeToAvoidBottomInset: false,
drawer: navigationMode == NavigationMode.drawer ? drawer : null,
appBar: AppBar(
scrolledUnderElevation: navigationMode != NavigationMode.drawer ? 0 : null,
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(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
if (appImplementations.data != null && activeAppIDSnapshot.hasData) ...[
Flexible(
child: Text(
appImplementations.data!
.find(activeAppIDSnapshot.data!)!
.name(context),
),
),
],
if (appImplementations.error != null) ...[
const SizedBox(
width: 8,
),
NeonException(
appImplementations.error,
onRetry: _appsBloc.refresh,
onlyIcon: true,
),
],
if (appImplementations.loading) ...[
const SizedBox(
width: 8,
),
Expanded(
child: NeonLinearProgressIndicator(
color: Theme.of(context).appBarTheme.foregroundColor,
),
),
],
],
),
if (accounts.length > 1) ...[
Text(
account.client.humanReadableID,
style: Theme.of(context).textTheme.bodySmall,
),
],
],
), ),
actions: [ NeonLinearProgressIndicator(
if (notificationsAppImplementation.data != null) ...[ visible: appImplementations.loading,
),
if (appImplementations.data != null) ...[
for (final appImplementation in appImplementations.data!) ...[
StreamBuilder<int>( StreamBuilder<int>(
stream: notificationsAppImplementation.data!.getUnreadCounter(_appsBloc), stream: appImplementation.getUnreadCounter(_appsBloc) ??
BehaviorSubject<int>.seeded(0),
builder: (final context, final unreadCounterSnapshot) { builder: (final context, final unreadCounterSnapshot) {
final unreadCount = unreadCounterSnapshot.data ?? 0; final unreadCount = unreadCounterSnapshot.data ?? 0;
return IconButton( if (isQuickBar) {
key: Key('app-${notificationsAppImplementation.data!.id}'), return IconButton(
onPressed: () async { onPressed: () async {
await _openNotifications( await _appsBloc.setActiveApp(appImplementation.id);
notificationsAppImplementation.data!, },
accounts, tooltip: appImplementation.name(context),
account, icon: NeonAppImplementationIcon(
); appImplementation: appImplementation,
}, unreadCount: unreadCount,
tooltip: AppLocalizations.of(context) color: Theme.of(context).colorScheme.primary,
.appImplementationName(notificationsAppImplementation.data!.id), ),
icon: NeonAppImplementationIcon( );
appImplementation: notificationsAppImplementation.data!, }
unreadCount: unreadCount, return ListTile(
color: unreadCount > 0 key: Key('app-${appImplementation.id}'),
? Theme.of(context).colorScheme.primary title: Row(
: Theme.of(context).colorScheme.onBackground, mainAxisAlignment: MainAxisAlignment.spaceBetween,
size: const Size.square(kAvatarSize * 2 / 3), 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) {
return;
}
Scaffold.maybeOf(context)?.closeDrawer();
},
); );
}, },
), ),
], ],
IconButton(
onPressed: () {
AccountSettingsRoute(accountid: account.id).go(context);
},
tooltip: AppLocalizations.of(context).settingsAccount,
icon: IntrinsicWidth(
child: NeonAccountAvatar(
account: account,
),
),
),
], ],
), ],
body: Row( ),
children: [ ),
if (navigationMode == NavigationMode.quickBar) ...[ ),
drawer, if (isQuickBar) ...[
], IconButton(
Expanded( onPressed: () => const SettingsRoute().go(context),
child: Column( tooltip: AppLocalizations.of(context).settings,
children: [ icon: Icon(
if (appImplementations.data != null) ...[ Icons.settings,
if (appImplementations.data!.isEmpty) ...[ color: Theme.of(context).appBarTheme.foregroundColor,
Expanded( ),
child: Center( ),
child: Text( ] else ...[
AppLocalizations.of(context) ListTile(
.errorNoCompatibleNextcloudAppsFound, key: const Key('settings'),
textAlign: TextAlign.center, title: Text(AppLocalizations.of(context).settings),
), leading: const Icon(Icons.settings),
), minLeadingWidth: 0,
), onTap: () async {
] else ...[ Scaffold.maybeOf(context)?.closeDrawer();
if (activeAppIDSnapshot.hasData) ...[ const SettingsRoute().go(context);
Expanded( },
child: appImplementations.data! ),
.find(activeAppIDSnapshot.data!)! ],
.buildPage(context, _appsBloc), ],
), ),
], ),
], ),
], );
], final appBar = AppBar(
), scrolledUnderElevation: navigationMode != NavigationMode.drawer ? 0 : null,
), 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(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
if (appImplementations.data != null && activeAppIDSnapshot.hasData) ...[
Flexible(
child: Text(
appImplementations.data!.find(activeAppIDSnapshot.data!)!.name(context),
),
),
],
if (appImplementations.error != null) ...[
const SizedBox(
width: 8,
),
NeonException(
appImplementations.error,
onRetry: _appsBloc.refresh,
onlyIcon: true,
),
],
if (appImplementations.loading) ...[
const SizedBox(
width: 8,
),
Expanded(
child: NeonLinearProgressIndicator(
color: Theme.of(context).appBarTheme.foregroundColor,
), ),
), ),
], ],
); ],
} ),
if (accounts.length > 1) ...[
Text(
account.client.humanReadableID,
style: Theme.of(context).textTheme.bodySmall,
),
],
],
),
actions: [
if (notificationsAppImplementation.data != null) ...[
StreamBuilder<int>(
stream: notificationsAppImplementation.data!.getUnreadCounter(_appsBloc),
builder: (final context, final unreadCounterSnapshot) {
final unreadCount = unreadCounterSnapshot.data ?? 0;
return IconButton(
key: Key('app-${notificationsAppImplementation.data!.id}'),
onPressed: () async {
await _openNotifications(
notificationsAppImplementation.data!,
accounts,
account,
);
},
tooltip: AppLocalizations.of(context)
.appImplementationName(notificationsAppImplementation.data!.id),
icon: NeonAppImplementationIcon(
appImplementation: notificationsAppImplementation.data!,
unreadCount: unreadCount,
color: unreadCount > 0
? Theme.of(context).colorScheme.primary
: Theme.of(context).colorScheme.onBackground,
size: const Size.square(kAvatarSize * 2 / 3),
),
);
},
),
],
IconButton(
onPressed: () {
AccountSettingsRoute(accountid: account.id).go(context);
},
tooltip: AppLocalizations.of(context).settingsAccount,
icon: IntrinsicWidth(
child: NeonAccountAvatar(
account: account,
),
),
),
],
);
final body = Builder(
builder: (final context) => Row(
children: [
if (navigationMode == NavigationMode.quickBar) ...[
drawer,
],
Expanded(
child: Column(
children: [
if (appImplementations.data != null) ...[
if (appImplementations.data!.isEmpty) ...[
Expanded(
child: Center(
child: Text(
AppLocalizations.of(context).errorNoCompatibleNextcloudAppsFound,
textAlign: TextAlign.center,
),
),
),
] else ...[
if (activeAppIDSnapshot.hasData) ...[
Expanded(
child: appImplementations.data!
.find(activeAppIDSnapshot.data!)!
.buildPage(context, _appsBloc),
),
],
],
],
],
),
),
],
),
);
return WillPopScope(
onWillPop: () async {
if (_scaffoldKey.currentState!.isDrawerOpen) {
Navigator.pop(context);
return true;
} }
return const Scaffold();
_scaffoldKey.currentState!.openDrawer();
return false;
}, },
), child: Row(
), children: [
if (navigationMode == NavigationMode.drawerAlwaysVisible) ...[
drawer,
],
Expanded(
child: Scaffold(
key: _scaffoldKey,
resizeToAvoidBottomInset: false,
drawer: navigationMode == NavigationMode.drawer ? drawer : null,
appBar: appBar,
body: body,
),
),
],
),
);
},
), ),
), ),
), ),

Loading…
Cancel
Save