Browse Source

Merge pull request #265 from provokateurin/feature/files-navigation

Add proper files navigation
pull/266/head
Kate 2 years ago committed by GitHub
parent
commit
e146c81397
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      packages/neon/neon/lib/neon.dart
  2. 76
      packages/neon/neon/lib/src/app.dart
  3. 8
      packages/neon/neon/lib/src/pages/home.dart
  4. 10
      packages/neon/neon/lib/src/pages/login.dart
  5. 51
      packages/neon/neon/lib/src/router.dart
  6. 20
      packages/neon/neon_files/lib/widgets/browser_view.dart
  7. 8
      packages/neon/neon_news/lib/pages/article.dart
  8. 6
      packages/neon/neon_notes/lib/pages/note.dart

1
packages/neon/neon/lib/neon.dart

@ -66,6 +66,7 @@ part 'src/platform/abstract.dart';
part 'src/platform/android.dart'; part 'src/platform/android.dart';
part 'src/platform/linux.dart'; part 'src/platform/linux.dart';
part 'src/platform/platform.dart'; part 'src/platform/platform.dart';
part 'src/router.dart';
part 'src/utils/account_options.dart'; part 'src/utils/account_options.dart';
part 'src/utils/app_implementation.dart'; part 'src/utils/app_implementation.dart';
part 'src/utils/bloc.dart'; part 'src/utils/bloc.dart';

76
packages/neon/neon/lib/src/app.dart

@ -25,7 +25,15 @@ class _NeonAppState extends State<NeonApp> with WidgetsBindingObserver, tray.Tra
late NeonPlatform _platform; late NeonPlatform _platform;
late GlobalOptions _globalOptions; late GlobalOptions _globalOptions;
late AccountsBloc _accountsBloc; late AccountsBloc _accountsBloc;
final _globalPopups = const GlobalPopups(); late final _routerDelegate = AppRouter(
navigatorKey: _navigatorKey,
accountsBloc: _accountsBloc,
onThemeChanged: (final nextcloudTheme) {
setState(() {
_nextcloudTheme = nextcloudTheme;
});
},
);
NextcloudCoreServerCapabilities_Ocs_Data_Capabilities_Theming? _nextcloudTheme; NextcloudCoreServerCapabilities_Ocs_Data_Capabilities_Theming? _nextcloudTheme;
final _platformBrightness = BehaviorSubject<Brightness>.seeded(WidgetsBinding.instance.window.platformBrightness); final _platformBrightness = BehaviorSubject<Brightness>.seeded(WidgetsBinding.instance.window.platformBrightness);
@ -55,50 +63,6 @@ class _NeonAppState extends State<NeonApp> with WidgetsBindingObserver, tray.Tra
} }
WidgetsBinding.instance.addPostFrameCallback((final _) async { WidgetsBinding.instance.addPostFrameCallback((final _) async {
widget.accountsBloc.activeAccount.listen((final activeAccount) async {
FlutterNativeSplash.remove();
if (activeAccount == null) {
await _navigatorKey.currentState!.pushAndRemoveUntil(
MaterialPageRoute(
builder: (final context) => const LoginPage(),
),
(final _) => false,
);
} else {
const settings = RouteSettings(
name: 'home',
);
Widget builder(final context) => Scaffold(
resizeToAvoidBottomInset: false,
body: Stack(
children: [
_globalPopups,
HomePage(
account: activeAccount,
onThemeChanged: (final nextcloudTheme) {
setState(() {
_nextcloudTheme = nextcloudTheme;
});
},
),
],
),
);
await _navigatorKey.currentState!.pushAndRemoveUntil(
widget.globalOptions.navigationMode.value == NavigationMode.drawer
? MaterialPageRoute(
settings: settings,
builder: builder,
)
: _NoAnimationPageRoute(
settings: settings,
builder: builder,
),
(final _) => false,
);
}
});
final localizations = await appLocalizationsFromSystem(); final localizations = await appLocalizationsFromSystem();
if (!mounted) { if (!mounted) {
@ -310,14 +274,17 @@ class _NeonAppState extends State<NeonApp> with WidgetsBindingObserver, tray.Tra
option: widget.globalOptions.themeOLEDAsDark, option: widget.globalOptions.themeOLEDAsDark,
builder: (final context, final themeOLEDAsDark) => OptionBuilder( builder: (final context, final themeOLEDAsDark) => OptionBuilder(
option: widget.globalOptions.themeKeepOriginalAccentColor, option: widget.globalOptions.themeKeepOriginalAccentColor,
builder: (final context, final themeKeepOriginalAccentColor) { builder: (final context, final themeKeepOriginalAccentColor) => StreamBuilder<Account?>(
stream: widget.accountsBloc.activeAccount,
builder: (final context, final activeAccountSnapshot) {
if (themeMode == null || !platformBrightnessSnapshot.hasData || themeOLEDAsDark == null) { if (themeMode == null || !platformBrightnessSnapshot.hasData || themeOLEDAsDark == null) {
return Container(); return Container();
} }
return MaterialApp(
FlutterNativeSplash.remove();
return MaterialApp.router(
localizationsDelegates: AppLocalizations.localizationsDelegates, localizationsDelegates: AppLocalizations.localizationsDelegates,
supportedLocales: AppLocalizations.supportedLocales, supportedLocales: AppLocalizations.supportedLocales,
navigatorKey: _navigatorKey,
theme: getThemeFromNextcloudTheme( theme: getThemeFromNextcloudTheme(
_nextcloudTheme, _nextcloudTheme,
themeMode, themeMode,
@ -325,21 +292,12 @@ class _NeonAppState extends State<NeonApp> with WidgetsBindingObserver, tray.Tra
oledAsDark: themeOLEDAsDark, oledAsDark: themeOLEDAsDark,
keepOriginalAccentColor: _nextcloudTheme == null || (themeKeepOriginalAccentColor ?? false), keepOriginalAccentColor: _nextcloudTheme == null || (themeKeepOriginalAccentColor ?? false),
), ),
home: Container(), routerDelegate: _routerDelegate,
); );
}, },
), ),
), ),
), ),
),
); );
} }
class _NoAnimationPageRoute extends MaterialPageRoute {
_NoAnimationPageRoute({
required super.builder,
super.settings,
});
@override
Duration get transitionDuration => Duration.zero;
}

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

@ -202,15 +202,15 @@ 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) => BackButtonListener(
onWillPop: () async { onBackButtonPressed: () async {
if (_scaffoldKey.currentState!.isDrawerOpen) { if (_scaffoldKey.currentState!.isDrawerOpen) {
Navigator.pop(context); Navigator.pop(context);
return true; return false;
} }
_scaffoldKey.currentState!.openDrawer(); _scaffoldKey.currentState!.openDrawer();
return false; return true;
}, },
child: Builder( child: Builder(
builder: (final context) { builder: (final context) {

10
packages/neon/neon/lib/src/pages/login.dart

@ -90,18 +90,18 @@ class _LoginPageState extends State<LoginPage> {
@override @override
Widget build(final BuildContext context) => StreamBuilder<List<Account>>( Widget build(final BuildContext context) => StreamBuilder<List<Account>>(
stream: _accountsBloc.accounts, stream: _accountsBloc.accounts,
builder: (final context, final accountsSnapshot) => WillPopScope( builder: (final context, final accountsSnapshot) => BackButtonListener(
onWillPop: () async { onBackButtonPressed: () async {
if (accountsSnapshot.data?.isNotEmpty ?? false) { if (accountsSnapshot.data?.isNotEmpty ?? false) {
return true; return false;
} }
if ((await _loginBloc.serverURL.first) == null) { if ((await _loginBloc.serverURL.first) == null) {
return true; return false;
} }
_loginBloc.setServerURL(null); _loginBloc.setServerURL(null);
return false; return true;
}, },
child: StreamBuilder<String?>( child: StreamBuilder<String?>(
stream: _loginBloc.serverURL, stream: _loginBloc.serverURL,

51
packages/neon/neon/lib/src/router.dart

@ -0,0 +1,51 @@
part of '../neon.dart';
// ignore: prefer_mixin
class AppRouter extends RouterDelegate<Account> with ChangeNotifier, PopNavigatorRouterDelegateMixin<Account> {
AppRouter({
required this.navigatorKey,
required this.accountsBloc,
required this.onThemeChanged,
});
final AccountsBloc accountsBloc;
final Function(NextcloudTheme? theme) onThemeChanged;
final _globalPopups = const GlobalPopups();
@override
final GlobalKey<NavigatorState> navigatorKey;
@override
Future setNewRoutePath(final Account? configuration) async {}
@override
Account? get currentConfiguration => accountsBloc.activeAccount.valueOrNull;
@override
Widget build(final BuildContext context) => Navigator(
key: navigatorKey,
onPopPage: (final route, final result) => route.didPop(result),
pages: [
if (currentConfiguration == null) ...[
const MaterialPage(
child: LoginPage(),
),
] else ...[
MaterialPage(
child: Scaffold(
resizeToAvoidBottomInset: false,
body: Stack(
children: [
_globalPopups,
HomePage(
account: currentConfiguration!,
onThemeChanged: onThemeChanged,
),
],
),
),
),
],
],
);
}

20
packages/neon/neon_files/lib/widgets/browser_view.dart

@ -46,7 +46,16 @@ class _FilesBrowserViewState extends State<FilesBrowserView> {
!uploadTasksSnapshot.hasData || !uploadTasksSnapshot.hasData ||
!downloadTasksSnapshot.hasData !downloadTasksSnapshot.hasData
? Container() ? Container()
: Scaffold( : BackButtonListener(
onBackButtonPressed: () async {
final path = pathSnapshot.data!;
if (path.isNotEmpty) {
widget.bloc.setPath(path.sublist(0, path.length - 1));
return true;
}
return false;
},
child: Scaffold(
resizeToAvoidBottomInset: false, resizeToAvoidBottomInset: false,
floatingActionButton: widget.enableCreateActions floatingActionButton: widget.enableCreateActions
? FloatingActionButton( ? FloatingActionButton(
@ -69,8 +78,9 @@ class _FilesBrowserViewState extends State<FilesBrowserView> {
for (final uploadTask in files.data == null for (final uploadTask in files.data == null
? <UploadTask>[] ? <UploadTask>[]
: uploadTasksSnapshot.data!.where( : uploadTasksSnapshot.data!.where(
(final task) => (final task) => files.data!
files.data!.where((final file) => _pathMatchesFile(task.path, file.name)).isEmpty, .where((final file) => _pathMatchesFile(task.path, file.name))
.isEmpty,
)) ...[ )) ...[
StreamBuilder<int>( StreamBuilder<int>(
stream: uploadTask.progress, stream: uploadTask.progress,
@ -108,7 +118,8 @@ class _FilesBrowserViewState extends State<FilesBrowserView> {
stream: matchingUploadTasks.isNotEmpty stream: matchingUploadTasks.isNotEmpty
? matchingUploadTasks.first.progress ? matchingUploadTasks.first.progress
: Stream.value(null), : Stream.value(null),
builder: (final context, final uploadTaskProgressSnapshot) => StreamBuilder<int?>( builder: (final context, final uploadTaskProgressSnapshot) =>
StreamBuilder<int?>(
stream: matchingDownloadTasks.isNotEmpty stream: matchingDownloadTasks.isNotEmpty
? matchingDownloadTasks.first.progress ? matchingDownloadTasks.first.progress
: Stream.value(null), : Stream.value(null),
@ -187,6 +198,7 @@ class _FilesBrowserViewState extends State<FilesBrowserView> {
), ),
), ),
), ),
),
); );
bool _pathMatchesFile(final List<String> path, final String name) => const ListEquality().equals( bool _pathMatchesFile(final List<String> path, final String name) => const ListEquality().equals(

8
packages/neon/neon_news/lib/pages/article.dart

@ -81,17 +81,17 @@ class _NewsArticlePageState extends State<NewsArticlePage> {
} }
@override @override
Widget build(final BuildContext context) => WillPopScope( Widget build(final BuildContext context) => BackButtonListener(
onWillPop: () async { onBackButtonPressed: () async {
if (_webviewController != null && await _webviewController!.canGoBack()) { if (_webviewController != null && await _webviewController!.canGoBack()) {
await _webviewController!.goBack(); await _webviewController!.goBack();
return false; return true;
} }
if (mounted && Provider.of<NeonPlatform>(context, listen: false).canUseWakelock) { if (mounted && Provider.of<NeonPlatform>(context, listen: false).canUseWakelock) {
await Wakelock.disable(); await Wakelock.disable();
} }
return true; return false;
}, },
child: Scaffold( child: Scaffold(
resizeToAvoidBottomInset: false, resizeToAvoidBottomInset: false,

6
packages/neon/neon_notes/lib/pages/note.dart

@ -63,12 +63,12 @@ class _NotesNotePageState extends State<NotesNotePage> {
} }
@override @override
Widget build(final BuildContext context) => WillPopScope( Widget build(final BuildContext context) => BackButtonListener(
onWillPop: () async { onBackButtonPressed: () async {
if (Provider.of<NeonPlatform>(context, listen: false).canUseWakelock) { if (Provider.of<NeonPlatform>(context, listen: false).canUseWakelock) {
await Wakelock.disable(); await Wakelock.disable();
} }
return true; return false;
}, },
child: Scaffold( child: Scaffold(
resizeToAvoidBottomInset: true, resizeToAvoidBottomInset: true,

Loading…
Cancel
Save