Bubble up selected folders to top
This commit is contained in:
parent
fcaa17624c
commit
422a398d07
|
@ -1,4 +1,8 @@
|
||||||
|
import 'dart:ui';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:implicitly_animated_reorderable_list/implicitly_animated_reorderable_list.dart';
|
||||||
|
import 'package:implicitly_animated_reorderable_list/transitions.dart';
|
||||||
import 'package:photos/core/configuration.dart';
|
import 'package:photos/core/configuration.dart';
|
||||||
import 'package:photos/core/event_bus.dart';
|
import 'package:photos/core/event_bus.dart';
|
||||||
import 'package:photos/db/files_db.dart';
|
import 'package:photos/db/files_db.dart';
|
||||||
|
@ -25,13 +29,12 @@ class BackupFolderSelectionPage extends StatefulWidget {
|
||||||
|
|
||||||
class _BackupFolderSelectionPageState extends State<BackupFolderSelectionPage> {
|
class _BackupFolderSelectionPageState extends State<BackupFolderSelectionPage> {
|
||||||
final Set<String> _allFolders = Set<String>();
|
final Set<String> _allFolders = Set<String>();
|
||||||
Set<String> _backedupFolders = Set<String>();
|
Set<String> _selectedFolders = Set<String>();
|
||||||
List<File> _latestFiles;
|
List<File> _latestFiles;
|
||||||
bool _isSelectAll = false;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
_backedupFolders = Configuration.instance.getPathsToBackUp();
|
_selectedFolders = Configuration.instance.getPathsToBackUp();
|
||||||
FilesDB.instance.getLatestLocalFiles().then((files) {
|
FilesDB.instance.getLatestLocalFiles().then((files) {
|
||||||
setState(() {
|
setState(() {
|
||||||
_latestFiles = files;
|
_latestFiles = files;
|
||||||
|
@ -39,9 +42,8 @@ class _BackupFolderSelectionPageState extends State<BackupFolderSelectionPage> {
|
||||||
_allFolders.add(file.deviceFolder);
|
_allFolders.add(file.deviceFolder);
|
||||||
}
|
}
|
||||||
if (widget.shouldSelectAll) {
|
if (widget.shouldSelectAll) {
|
||||||
_backedupFolders.addAll(_allFolders);
|
_selectedFolders.addAll(_allFolders);
|
||||||
}
|
}
|
||||||
_isSelectAll = _backedupFolders.length == _allFolders.length;
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
super.initState();
|
super.initState();
|
||||||
|
@ -79,7 +81,9 @@ class _BackupFolderSelectionPageState extends State<BackupFolderSelectionPage> {
|
||||||
child: Align(
|
child: Align(
|
||||||
alignment: Alignment.centerRight,
|
alignment: Alignment.centerRight,
|
||||||
child: Text(
|
child: Text(
|
||||||
_isSelectAll ? "unselect all" : "select all",
|
_selectedFolders.length == _allFolders.length
|
||||||
|
? "unselect all"
|
||||||
|
: "select all",
|
||||||
textAlign: TextAlign.right,
|
textAlign: TextAlign.right,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
|
@ -89,15 +93,17 @@ class _BackupFolderSelectionPageState extends State<BackupFolderSelectionPage> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
_isSelectAll = !_isSelectAll;
|
final hasSelectedAll =
|
||||||
if (_isSelectAll) {
|
_selectedFolders.length == _allFolders.length;
|
||||||
_backedupFolders.addAll(_allFolders);
|
// Flip selection
|
||||||
|
if (hasSelectedAll) {
|
||||||
|
_selectedFolders.clear();
|
||||||
} else {
|
} else {
|
||||||
_backedupFolders.clear();
|
_selectedFolders.addAll(_allFolders);
|
||||||
}
|
}
|
||||||
setState(() {});
|
setState(() {});
|
||||||
}),
|
}),
|
||||||
Expanded(child: _getFolderList()),
|
Expanded(child: _getFolders()),
|
||||||
Padding(
|
Padding(
|
||||||
padding: EdgeInsets.all(20),
|
padding: EdgeInsets.all(20),
|
||||||
),
|
),
|
||||||
|
@ -108,11 +114,11 @@ class _BackupFolderSelectionPageState extends State<BackupFolderSelectionPage> {
|
||||||
child: button(
|
child: button(
|
||||||
widget.buttonText,
|
widget.buttonText,
|
||||||
fontSize: 18,
|
fontSize: 18,
|
||||||
onPressed: _backedupFolders.length == 0
|
onPressed: _selectedFolders.length == 0
|
||||||
? null
|
? null
|
||||||
: () async {
|
: () async {
|
||||||
await Configuration.instance
|
await Configuration.instance
|
||||||
.setPathsToBackUp(_backedupFolders);
|
.setPathsToBackUp(_selectedFolders);
|
||||||
Bus.instance.fire(BackupFoldersUpdatedEvent());
|
Bus.instance.fire(BackupFoldersUpdatedEvent());
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
},
|
},
|
||||||
|
@ -128,16 +134,81 @@ class _BackupFolderSelectionPageState extends State<BackupFolderSelectionPage> {
|
||||||
Widget _getFolderList() {
|
Widget _getFolderList() {
|
||||||
Widget child;
|
Widget child;
|
||||||
if (_latestFiles != null) {
|
if (_latestFiles != null) {
|
||||||
_latestFiles.sort((first, second) {
|
final foldersWidget = _getFolders();
|
||||||
return first.deviceFolder
|
final scrollController = ScrollController();
|
||||||
.toLowerCase()
|
child = Scrollbar(
|
||||||
.compareTo(second.deviceFolder.toLowerCase());
|
isAlwaysShown: true,
|
||||||
|
controller: scrollController,
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
controller: scrollController,
|
||||||
|
child: Container(
|
||||||
|
padding: EdgeInsets.only(right: 4),
|
||||||
|
child: foldersWidget,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
child = loadWidget;
|
||||||
|
}
|
||||||
|
return Container(
|
||||||
|
padding: EdgeInsets.only(left: 40, right: 40),
|
||||||
|
child: child,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _getFolders() {
|
||||||
|
if (_latestFiles == null) {
|
||||||
|
return Container();
|
||||||
|
}
|
||||||
|
_sortFiles();
|
||||||
|
final scrollController = ScrollController();
|
||||||
|
return Container(
|
||||||
|
padding: EdgeInsets.only(left: 40, right: 40),
|
||||||
|
child: Scrollbar(
|
||||||
|
controller: scrollController,
|
||||||
|
isAlwaysShown: true,
|
||||||
|
child: ImplicitlyAnimatedReorderableList<File>(
|
||||||
|
controller: scrollController,
|
||||||
|
items: _latestFiles,
|
||||||
|
areItemsTheSame: (oldItem, newItem) =>
|
||||||
|
oldItem.deviceFolder == newItem.deviceFolder,
|
||||||
|
onReorderFinished: (item, from, to, newItems) {
|
||||||
|
setState(() {
|
||||||
|
_latestFiles
|
||||||
|
..clear()
|
||||||
|
..addAll(newItems);
|
||||||
});
|
});
|
||||||
final List<Widget> foldersWidget = [];
|
},
|
||||||
for (final file in _latestFiles) {
|
itemBuilder: (context, itemAnimation, file, index) {
|
||||||
final isSelected = _backedupFolders.contains(file.deviceFolder);
|
return Reorderable(
|
||||||
foldersWidget.add(
|
key: ValueKey(file),
|
||||||
Padding(
|
builder: (context, dragAnimation, inDrag) {
|
||||||
|
final t = dragAnimation.value;
|
||||||
|
final elevation = lerpDouble(0, 8, t);
|
||||||
|
final color =
|
||||||
|
Color.lerp(Colors.white, Colors.white.withOpacity(0.8), t);
|
||||||
|
return SizeFadeTransition(
|
||||||
|
sizeFraction: 0.7,
|
||||||
|
curve: Curves.easeInOut,
|
||||||
|
animation: itemAnimation,
|
||||||
|
child: Material(
|
||||||
|
color: color,
|
||||||
|
elevation: elevation,
|
||||||
|
type: MaterialType.transparency,
|
||||||
|
child: _getFileItem(file),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Padding _getFileItem(File file) {
|
||||||
|
final isSelected = _selectedFolders.contains(file.deviceFolder);
|
||||||
|
return Padding(
|
||||||
padding: const EdgeInsets.only(bottom: 1, right: 4),
|
padding: const EdgeInsets.only(bottom: 1, right: 4),
|
||||||
child: Container(
|
child: Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
|
@ -177,9 +248,9 @@ class _BackupFolderSelectionPageState extends State<BackupFolderSelectionPage> {
|
||||||
value: isSelected,
|
value: isSelected,
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
if (value) {
|
if (value) {
|
||||||
_backedupFolders.add(file.deviceFolder);
|
_selectedFolders.add(file.deviceFolder);
|
||||||
} else {
|
} else {
|
||||||
_backedupFolders.remove(file.deviceFolder);
|
_selectedFolders.remove(file.deviceFolder);
|
||||||
}
|
}
|
||||||
setState(() {});
|
setState(() {});
|
||||||
},
|
},
|
||||||
|
@ -187,42 +258,31 @@ class _BackupFolderSelectionPageState extends State<BackupFolderSelectionPage> {
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
final value = !_backedupFolders.contains(file.deviceFolder);
|
final value = !_selectedFolders.contains(file.deviceFolder);
|
||||||
if (value) {
|
if (value) {
|
||||||
_backedupFolders.add(file.deviceFolder);
|
_selectedFolders.add(file.deviceFolder);
|
||||||
} else {
|
} else {
|
||||||
_backedupFolders.remove(file.deviceFolder);
|
_selectedFolders.remove(file.deviceFolder);
|
||||||
}
|
}
|
||||||
setState(() {});
|
setState(() {});
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
final scrollController = ScrollController();
|
void _sortFiles() {
|
||||||
child = Scrollbar(
|
_latestFiles.sort((first, second) {
|
||||||
isAlwaysShown: true,
|
if (_selectedFolders.contains(first) &&
|
||||||
controller: scrollController,
|
_selectedFolders.contains(second)) {
|
||||||
child: SingleChildScrollView(
|
return first.deviceFolder.compareTo(second.deviceFolder);
|
||||||
controller: scrollController,
|
} else if (_selectedFolders.contains(first.deviceFolder)) {
|
||||||
child: Container(
|
return -1;
|
||||||
padding: EdgeInsets.only(right: 4),
|
} else if (_selectedFolders.contains(second.deviceFolder)) {
|
||||||
child: Column(
|
return 1;
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
||||||
children: foldersWidget,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
child = loadWidget;
|
|
||||||
}
|
}
|
||||||
return Container(
|
return first.deviceFolder.compareTo(second.deviceFolder);
|
||||||
padding: EdgeInsets.only(left: 40, right: 40),
|
});
|
||||||
child: child,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _getThumbnail(File file) {
|
Widget _getThumbnail(File file) {
|
||||||
|
|
|
@ -466,6 +466,13 @@ packages:
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.0"
|
version: "1.0.0"
|
||||||
|
implicitly_animated_reorderable_list:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: implicitly_animated_reorderable_list
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "0.4.0"
|
||||||
in_app_purchase:
|
in_app_purchase:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|
|
@ -94,6 +94,7 @@ dependencies:
|
||||||
device_info: ^2.0.2
|
device_info: ^2.0.2
|
||||||
exif: ^3.0.0
|
exif: ^3.0.0
|
||||||
wallpaper_manager_flutter: ^0.0.2
|
wallpaper_manager_flutter: ^0.0.2
|
||||||
|
implicitly_animated_reorderable_list: ^0.4.0
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
|
Loading…
Reference in a new issue