debug: improved page layout
This commit is contained in:
parent
895087f604
commit
528a83b750
17 changed files with 571 additions and 427 deletions
|
@ -1,370 +0,0 @@
|
||||||
import 'dart:collection';
|
|
||||||
|
|
||||||
import 'package:aves/model/favourite_repo.dart';
|
|
||||||
import 'package:aves/model/image_entry.dart';
|
|
||||||
import 'package:aves/model/image_metadata.dart';
|
|
||||||
import 'package:aves/model/metadata_db.dart';
|
|
||||||
import 'package:aves/model/settings/settings.dart';
|
|
||||||
import 'package:aves/model/source/collection_source.dart';
|
|
||||||
import 'package:aves/services/android_app_service.dart';
|
|
||||||
import 'package:aves/services/image_file_service.dart';
|
|
||||||
import 'package:aves/utils/android_file_utils.dart';
|
|
||||||
import 'package:aves/utils/file_utils.dart';
|
|
||||||
import 'package:aves/widgets/common/data_providers/media_query_data_provider.dart';
|
|
||||||
import 'package:aves/widgets/common/icons.dart';
|
|
||||||
import 'package:aves/widgets/fullscreen/info/common.dart';
|
|
||||||
import 'package:firebase_analytics/firebase_analytics.dart';
|
|
||||||
import 'package:firebase_core/firebase_core.dart';
|
|
||||||
import 'package:firebase_crashlytics/firebase_crashlytics.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter/scheduler.dart';
|
|
||||||
import 'package:flutter_svg/flutter_svg.dart';
|
|
||||||
|
|
||||||
class AppDebugPage extends StatefulWidget {
|
|
||||||
static const routeName = '/debug';
|
|
||||||
|
|
||||||
final CollectionSource source;
|
|
||||||
|
|
||||||
const AppDebugPage({this.source});
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<StatefulWidget> createState() => AppDebugPageState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class AppDebugPageState extends State<AppDebugPage> {
|
|
||||||
Future<int> _dbFileSizeLoader;
|
|
||||||
Future<List<ImageEntry>> _dbEntryLoader;
|
|
||||||
Future<List<DateMetadata>> _dbDateLoader;
|
|
||||||
Future<List<CatalogMetadata>> _dbMetadataLoader;
|
|
||||||
Future<List<AddressDetails>> _dbAddressLoader;
|
|
||||||
Future<List<FavouriteRow>> _dbFavouritesLoader;
|
|
||||||
Future<Map> _envLoader;
|
|
||||||
|
|
||||||
List<ImageEntry> get entries => widget.source.rawEntries;
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
_startDbReport();
|
|
||||||
_envLoader = AndroidAppService.getEnv();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return MediaQueryDataProvider(
|
|
||||||
child: DefaultTabController(
|
|
||||||
length: 4,
|
|
||||||
child: Scaffold(
|
|
||||||
appBar: AppBar(
|
|
||||||
title: Text('Debug'),
|
|
||||||
bottom: TabBar(
|
|
||||||
tabs: [
|
|
||||||
Tab(icon: Icon(AIcons.debug)),
|
|
||||||
Tab(icon: Icon(AIcons.settings)),
|
|
||||||
Tab(icon: Icon(AIcons.removableStorage)),
|
|
||||||
Tab(icon: Icon(AIcons.android)),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
body: SafeArea(
|
|
||||||
child: TabBarView(
|
|
||||||
children: [
|
|
||||||
_buildGeneralTabView(),
|
|
||||||
_buildSettingsTabView(),
|
|
||||||
_buildStorageTabView(),
|
|
||||||
_buildEnvTabView(),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildGeneralTabView() {
|
|
||||||
final catalogued = entries.where((entry) => entry.isCatalogued);
|
|
||||||
final withGps = catalogued.where((entry) => entry.hasGps);
|
|
||||||
final located = withGps.where((entry) => entry.isLocated);
|
|
||||||
return ListView(
|
|
||||||
padding: EdgeInsets.all(16),
|
|
||||||
children: [
|
|
||||||
Text('Time dilation'),
|
|
||||||
Slider(
|
|
||||||
value: timeDilation,
|
|
||||||
onChanged: (v) => setState(() => timeDilation = v),
|
|
||||||
min: 1.0,
|
|
||||||
max: 10.0,
|
|
||||||
divisions: 9,
|
|
||||||
label: '$timeDilation',
|
|
||||||
),
|
|
||||||
Divider(),
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: Text('Crashlytics'),
|
|
||||||
),
|
|
||||||
SizedBox(width: 8),
|
|
||||||
ElevatedButton(
|
|
||||||
onPressed: FirebaseCrashlytics.instance.crash,
|
|
||||||
child: Text('Crash'),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: Text('Analytics'),
|
|
||||||
),
|
|
||||||
SizedBox(width: 8),
|
|
||||||
ElevatedButton(
|
|
||||||
onPressed: () => FirebaseAnalytics().logEvent(
|
|
||||||
name: 'debug_test',
|
|
||||||
parameters: {'time': DateTime.now().toIso8601String()},
|
|
||||||
),
|
|
||||||
child: Text('Send event'),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
Text('Firebase data collection: ${Firebase.app().isAutomaticDataCollectionEnabled ? 'enabled' : 'disabled'}'),
|
|
||||||
Text('Crashlytics collection: ${FirebaseCrashlytics.instance.isCrashlyticsCollectionEnabled ? 'enabled' : 'disabled'}'),
|
|
||||||
Divider(),
|
|
||||||
Text('Entries: ${entries.length}'),
|
|
||||||
Text('Catalogued: ${catalogued.length}'),
|
|
||||||
Text('With GPS: ${withGps.length}'),
|
|
||||||
Text('With address: ${located.length}'),
|
|
||||||
Divider(),
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: Text('Image cache:\n\t${imageCache.currentSize}/${imageCache.maximumSize} items\n\t${formatFilesize(imageCache.currentSizeBytes)}/${formatFilesize(imageCache.maximumSizeBytes)}'),
|
|
||||||
),
|
|
||||||
SizedBox(width: 8),
|
|
||||||
ElevatedButton(
|
|
||||||
onPressed: () {
|
|
||||||
imageCache.clear();
|
|
||||||
setState(() {});
|
|
||||||
},
|
|
||||||
child: Text('Clear'),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: Text('SVG cache: ${PictureProvider.cacheCount} items'),
|
|
||||||
),
|
|
||||||
SizedBox(width: 8),
|
|
||||||
ElevatedButton(
|
|
||||||
onPressed: () {
|
|
||||||
PictureProvider.clearCache();
|
|
||||||
setState(() {});
|
|
||||||
},
|
|
||||||
child: Text('Clear'),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: Text('Glide disk cache: ?'),
|
|
||||||
),
|
|
||||||
SizedBox(width: 8),
|
|
||||||
ElevatedButton(
|
|
||||||
onPressed: ImageFileService.clearSizedThumbnailDiskCache,
|
|
||||||
child: Text('Clear'),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
Divider(),
|
|
||||||
FutureBuilder<int>(
|
|
||||||
future: _dbFileSizeLoader,
|
|
||||||
builder: (context, snapshot) {
|
|
||||||
if (snapshot.hasError) return Text(snapshot.error.toString());
|
|
||||||
if (snapshot.connectionState != ConnectionState.done) return SizedBox.shrink();
|
|
||||||
return Row(
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: Text('DB file size: ${formatFilesize(snapshot.data)}'),
|
|
||||||
),
|
|
||||||
SizedBox(width: 8),
|
|
||||||
ElevatedButton(
|
|
||||||
onPressed: () => metadataDb.reset().then((_) => _startDbReport()),
|
|
||||||
child: Text('Reset'),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
FutureBuilder<List>(
|
|
||||||
future: _dbEntryLoader,
|
|
||||||
builder: (context, snapshot) {
|
|
||||||
if (snapshot.hasError) return Text(snapshot.error.toString());
|
|
||||||
if (snapshot.connectionState != ConnectionState.done) return SizedBox.shrink();
|
|
||||||
return Row(
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: Text('DB entry rows: ${snapshot.data.length}'),
|
|
||||||
),
|
|
||||||
SizedBox(width: 8),
|
|
||||||
ElevatedButton(
|
|
||||||
onPressed: () => metadataDb.clearEntries().then((_) => _startDbReport()),
|
|
||||||
child: Text('Clear'),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
FutureBuilder<List>(
|
|
||||||
future: _dbDateLoader,
|
|
||||||
builder: (context, snapshot) {
|
|
||||||
if (snapshot.hasError) return Text(snapshot.error.toString());
|
|
||||||
if (snapshot.connectionState != ConnectionState.done) return SizedBox.shrink();
|
|
||||||
return Row(
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: Text('DB date rows: ${snapshot.data.length}'),
|
|
||||||
),
|
|
||||||
SizedBox(width: 8),
|
|
||||||
ElevatedButton(
|
|
||||||
onPressed: () => metadataDb.clearDates().then((_) => _startDbReport()),
|
|
||||||
child: Text('Clear'),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
FutureBuilder<List>(
|
|
||||||
future: _dbMetadataLoader,
|
|
||||||
builder: (context, snapshot) {
|
|
||||||
if (snapshot.hasError) return Text(snapshot.error.toString());
|
|
||||||
if (snapshot.connectionState != ConnectionState.done) return SizedBox.shrink();
|
|
||||||
return Row(
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: Text('DB metadata rows: ${snapshot.data.length}'),
|
|
||||||
),
|
|
||||||
SizedBox(width: 8),
|
|
||||||
ElevatedButton(
|
|
||||||
onPressed: () => metadataDb.clearMetadataEntries().then((_) => _startDbReport()),
|
|
||||||
child: Text('Clear'),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
FutureBuilder<List>(
|
|
||||||
future: _dbAddressLoader,
|
|
||||||
builder: (context, snapshot) {
|
|
||||||
if (snapshot.hasError) return Text(snapshot.error.toString());
|
|
||||||
if (snapshot.connectionState != ConnectionState.done) return SizedBox.shrink();
|
|
||||||
return Row(
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: Text('DB address rows: ${snapshot.data.length}'),
|
|
||||||
),
|
|
||||||
SizedBox(width: 8),
|
|
||||||
ElevatedButton(
|
|
||||||
onPressed: () => metadataDb.clearAddresses().then((_) => _startDbReport()),
|
|
||||||
child: Text('Clear'),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
FutureBuilder<List>(
|
|
||||||
future: _dbFavouritesLoader,
|
|
||||||
builder: (context, snapshot) {
|
|
||||||
if (snapshot.hasError) return Text(snapshot.error.toString());
|
|
||||||
if (snapshot.connectionState != ConnectionState.done) return SizedBox.shrink();
|
|
||||||
return Row(
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: Text('DB favourite rows: ${snapshot.data.length} (${favourites.count} in memory)'),
|
|
||||||
),
|
|
||||||
SizedBox(width: 8),
|
|
||||||
ElevatedButton(
|
|
||||||
onPressed: () => favourites.clear().then((_) => _startDbReport()),
|
|
||||||
child: Text('Clear'),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildSettingsTabView() {
|
|
||||||
return ListView(
|
|
||||||
padding: EdgeInsets.all(16),
|
|
||||||
children: [
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: Text('Settings'),
|
|
||||||
),
|
|
||||||
SizedBox(width: 8),
|
|
||||||
ElevatedButton(
|
|
||||||
onPressed: () => settings.reset().then((_) => setState(() {})),
|
|
||||||
child: Text('Reset'),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
InfoRowGroup({
|
|
||||||
'collectionGroupFactor': '${settings.collectionGroupFactor}',
|
|
||||||
'collectionSortFactor': '${settings.collectionSortFactor}',
|
|
||||||
'collectionTileExtent': '${settings.collectionTileExtent}',
|
|
||||||
'infoMapZoom': '${settings.infoMapZoom}',
|
|
||||||
'pinnedFilters': '${settings.pinnedFilters}',
|
|
||||||
'searchHistory': '${settings.searchHistory}',
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildStorageTabView() {
|
|
||||||
return ListView(
|
|
||||||
padding: EdgeInsets.all(16),
|
|
||||||
children: [
|
|
||||||
...androidFileUtils.storageVolumes.expand((v) => [
|
|
||||||
Text(v.path),
|
|
||||||
InfoRowGroup({
|
|
||||||
'description': '${v.description}',
|
|
||||||
'isEmulated': '${v.isEmulated}',
|
|
||||||
'isPrimary': '${v.isPrimary}',
|
|
||||||
'isRemovable': '${v.isRemovable}',
|
|
||||||
'state': '${v.state}',
|
|
||||||
}),
|
|
||||||
Divider(),
|
|
||||||
])
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildEnvTabView() {
|
|
||||||
return ListView(
|
|
||||||
padding: EdgeInsets.all(16),
|
|
||||||
children: [
|
|
||||||
FutureBuilder<Map>(
|
|
||||||
future: _envLoader,
|
|
||||||
builder: (context, snapshot) {
|
|
||||||
if (snapshot.hasError) return Text(snapshot.error.toString());
|
|
||||||
if (snapshot.connectionState != ConnectionState.done) return SizedBox.shrink();
|
|
||||||
final data = SplayTreeMap.of(snapshot.data.map((k, v) => MapEntry(k.toString(), v?.toString() ?? 'null')));
|
|
||||||
return InfoRowGroup(data);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _startDbReport() {
|
|
||||||
_dbFileSizeLoader = metadataDb.dbFileSize();
|
|
||||||
_dbEntryLoader = metadataDb.loadEntries();
|
|
||||||
_dbDateLoader = metadataDb.loadDates();
|
|
||||||
_dbMetadataLoader = metadataDb.loadMetadataEntries();
|
|
||||||
_dbAddressLoader = metadataDb.loadAddresses();
|
|
||||||
_dbFavouritesLoader = metadataDb.loadFavourites();
|
|
||||||
setState(() {});
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -214,7 +214,7 @@ class SectionSelectableLeading extends StatelessWidget {
|
||||||
child: IconButton(
|
child: IconButton(
|
||||||
iconSize: 26,
|
iconSize: 26,
|
||||||
padding: EdgeInsets.only(top: 1),
|
padding: EdgeInsets.only(top: 1),
|
||||||
alignment: Alignment.topLeft,
|
alignment: AlignmentDirectional.topStart,
|
||||||
icon: Icon(selected ? AIcons.selected : AIcons.unselected),
|
icon: Icon(selected ? AIcons.selected : AIcons.unselected),
|
||||||
onPressed: onPressed,
|
onPressed: onPressed,
|
||||||
tooltip: selected ? 'Deselect section' : 'Select section',
|
tooltip: selected ? 'Deselect section' : 'Select section',
|
||||||
|
|
|
@ -97,7 +97,7 @@ class ThumbnailSelectionOverlay extends StatelessWidget {
|
||||||
);
|
);
|
||||||
child = AnimatedContainer(
|
child = AnimatedContainer(
|
||||||
duration: duration,
|
duration: duration,
|
||||||
alignment: Alignment.topRight,
|
alignment: AlignmentDirectional.topEnd,
|
||||||
color: selected ? Colors.black54 : Colors.transparent,
|
color: selected ? Colors.black54 : Colors.transparent,
|
||||||
child: child,
|
child: child,
|
||||||
);
|
);
|
||||||
|
|
|
@ -9,12 +9,13 @@ class AvesExpansionTile extends StatelessWidget {
|
||||||
|
|
||||||
const AvesExpansionTile({
|
const AvesExpansionTile({
|
||||||
@required this.title,
|
@required this.title,
|
||||||
@required this.children,
|
|
||||||
this.expandedNotifier,
|
this.expandedNotifier,
|
||||||
|
@required this.children,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final enabled = children?.isNotEmpty == true;
|
||||||
return Theme(
|
return Theme(
|
||||||
data: Theme.of(context).copyWith(
|
data: Theme.of(context).copyWith(
|
||||||
// color used by the `ExpansionTileCard` for selected text and icons
|
// color used by the `ExpansionTileCard` for selected text and icons
|
||||||
|
@ -27,12 +28,17 @@ class AvesExpansionTile extends StatelessWidget {
|
||||||
title: HighlightTitle(
|
title: HighlightTitle(
|
||||||
title,
|
title,
|
||||||
fontSize: 18,
|
fontSize: 18,
|
||||||
|
enabled: enabled,
|
||||||
),
|
),
|
||||||
|
expandable: enabled,
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Divider(thickness: 1, height: 1),
|
Divider(thickness: 1, height: 1),
|
||||||
SizedBox(height: 4),
|
SizedBox(height: 4),
|
||||||
...children,
|
if (enabled) ...children,
|
||||||
],
|
],
|
||||||
|
),
|
||||||
baseColor: Colors.grey[900],
|
baseColor: Colors.grey[900],
|
||||||
expandedColor: Colors.grey[850],
|
expandedColor: Colors.grey[850],
|
||||||
),
|
),
|
||||||
|
|
|
@ -5,19 +5,23 @@ import 'package:flutter/material.dart';
|
||||||
class HighlightTitle extends StatelessWidget {
|
class HighlightTitle extends StatelessWidget {
|
||||||
final String name;
|
final String name;
|
||||||
final double fontSize;
|
final double fontSize;
|
||||||
|
final bool enabled;
|
||||||
|
|
||||||
const HighlightTitle(
|
const HighlightTitle(
|
||||||
this.name, {
|
this.name, {
|
||||||
this.fontSize = 20,
|
this.fontSize = 20,
|
||||||
|
this.enabled = true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
static const disabledColor = Colors.grey;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Align(
|
return Align(
|
||||||
alignment: AlignmentDirectional.centerStart,
|
alignment: AlignmentDirectional.centerStart,
|
||||||
child: Container(
|
child: Container(
|
||||||
decoration: HighlightDecoration(
|
decoration: HighlightDecoration(
|
||||||
color: stringToColor(name),
|
color: enabled ? stringToColor(name) : disabledColor,
|
||||||
),
|
),
|
||||||
margin: EdgeInsets.symmetric(vertical: 4.0),
|
margin: EdgeInsets.symmetric(vertical: 4.0),
|
||||||
child: Text(
|
child: Text(
|
||||||
|
|
47
lib/widgets/debug/android_env.dart
Normal file
47
lib/widgets/debug/android_env.dart
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
import 'dart:collection';
|
||||||
|
|
||||||
|
import 'package:aves/services/android_app_service.dart';
|
||||||
|
import 'package:aves/widgets/common/aves_expansion_tile.dart';
|
||||||
|
import 'package:aves/widgets/fullscreen/info/common.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class DebugAndroidEnvironmentSection extends StatefulWidget {
|
||||||
|
@override
|
||||||
|
_DebugAndroidEnvironmentSectionState createState() => _DebugAndroidEnvironmentSectionState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _DebugAndroidEnvironmentSectionState extends State<DebugAndroidEnvironmentSection> with AutomaticKeepAliveClientMixin {
|
||||||
|
Future<Map> _loader;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_loader = AndroidAppService.getEnv();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
super.build(context);
|
||||||
|
|
||||||
|
return AvesExpansionTile(
|
||||||
|
title: 'Android Environment',
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.only(left: 8, right: 8, bottom: 8),
|
||||||
|
child: FutureBuilder<Map>(
|
||||||
|
future: _loader,
|
||||||
|
builder: (context, snapshot) {
|
||||||
|
if (snapshot.hasError) return Text(snapshot.error.toString());
|
||||||
|
if (snapshot.connectionState != ConnectionState.done) return SizedBox.shrink();
|
||||||
|
final data = SplayTreeMap.of(snapshot.data.map((k, v) => MapEntry(k.toString(), v?.toString() ?? 'null')));
|
||||||
|
return InfoRowGroup(data);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool get wantKeepAlive => true;
|
||||||
|
}
|
88
lib/widgets/debug/app_debug_page.dart
Normal file
88
lib/widgets/debug/app_debug_page.dart
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
import 'package:aves/model/image_entry.dart';
|
||||||
|
import 'package:aves/model/source/collection_source.dart';
|
||||||
|
import 'package:aves/widgets/common/aves_expansion_tile.dart';
|
||||||
|
import 'package:aves/widgets/common/data_providers/media_query_data_provider.dart';
|
||||||
|
import 'package:aves/widgets/debug/android_env.dart';
|
||||||
|
import 'package:aves/widgets/debug/cache.dart';
|
||||||
|
import 'package:aves/widgets/debug/database.dart';
|
||||||
|
import 'package:aves/widgets/debug/firebase.dart';
|
||||||
|
import 'package:aves/widgets/debug/settings.dart';
|
||||||
|
import 'package:aves/widgets/debug/storage.dart';
|
||||||
|
import 'package:aves/widgets/fullscreen/info/common.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/scheduler.dart';
|
||||||
|
|
||||||
|
class AppDebugPage extends StatefulWidget {
|
||||||
|
static const routeName = '/debug';
|
||||||
|
|
||||||
|
final CollectionSource source;
|
||||||
|
|
||||||
|
const AppDebugPage({this.source});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<StatefulWidget> createState() => AppDebugPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class AppDebugPageState extends State<AppDebugPage> {
|
||||||
|
List<ImageEntry> get entries => widget.source.rawEntries;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return MediaQueryDataProvider(
|
||||||
|
child: Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: Text('Debug'),
|
||||||
|
),
|
||||||
|
body: SafeArea(
|
||||||
|
child: ListView(
|
||||||
|
padding: EdgeInsets.all(8),
|
||||||
|
children: [
|
||||||
|
_buildGeneralTabView(),
|
||||||
|
DebugAndroidEnvironmentSection(),
|
||||||
|
DebugCacheSection(),
|
||||||
|
DebugAppDatabaseSection(),
|
||||||
|
DebugFirebaseSection(),
|
||||||
|
DebugSettingsSection(),
|
||||||
|
DebugStorageSection(),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildGeneralTabView() {
|
||||||
|
final catalogued = entries.where((entry) => entry.isCatalogued);
|
||||||
|
final withGps = catalogued.where((entry) => entry.hasGps);
|
||||||
|
final located = withGps.where((entry) => entry.isLocated);
|
||||||
|
return AvesExpansionTile(
|
||||||
|
title: 'General',
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.all(8),
|
||||||
|
child: Text('Time dilation'),
|
||||||
|
),
|
||||||
|
Slider(
|
||||||
|
value: timeDilation,
|
||||||
|
onChanged: (v) => setState(() => timeDilation = v),
|
||||||
|
min: 1.0,
|
||||||
|
max: 10.0,
|
||||||
|
divisions: 9,
|
||||||
|
label: '$timeDilation',
|
||||||
|
),
|
||||||
|
Divider(),
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.only(left: 8, right: 8, bottom: 8),
|
||||||
|
child: InfoRowGroup(
|
||||||
|
{
|
||||||
|
'Entries': '${entries.length}',
|
||||||
|
'Catalogued': '${catalogued.length}',
|
||||||
|
'With GPS': '${withGps.length}',
|
||||||
|
'With address': '${located.length}',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
77
lib/widgets/debug/cache.dart
Normal file
77
lib/widgets/debug/cache.dart
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
import 'package:aves/services/image_file_service.dart';
|
||||||
|
import 'package:aves/utils/file_utils.dart';
|
||||||
|
import 'package:aves/widgets/common/aves_expansion_tile.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_svg/flutter_svg.dart';
|
||||||
|
|
||||||
|
class DebugCacheSection extends StatefulWidget {
|
||||||
|
@override
|
||||||
|
_DebugCacheSectionState createState() => _DebugCacheSectionState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _DebugCacheSectionState extends State<DebugCacheSection> with AutomaticKeepAliveClientMixin {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
super.build(context);
|
||||||
|
|
||||||
|
return AvesExpansionTile(
|
||||||
|
title: 'Cache',
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 8),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Text('Image cache:\n\t${imageCache.currentSize}/${imageCache.maximumSize} items\n\t${formatFilesize(imageCache.currentSizeBytes)}/${formatFilesize(imageCache.maximumSizeBytes)}'),
|
||||||
|
),
|
||||||
|
SizedBox(width: 8),
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: () {
|
||||||
|
imageCache.clear();
|
||||||
|
|
||||||
|
setState(() {});
|
||||||
|
},
|
||||||
|
child: Text('Clear'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Text('SVG cache: ${PictureProvider.cacheCount} items'),
|
||||||
|
),
|
||||||
|
SizedBox(width: 8),
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: () {
|
||||||
|
PictureProvider.clearCache();
|
||||||
|
|
||||||
|
setState(() {});
|
||||||
|
},
|
||||||
|
child: Text('Clear'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Text('Glide disk cache: ?'),
|
||||||
|
),
|
||||||
|
SizedBox(width: 8),
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: ImageFileService.clearSizedThumbnailDiskCache,
|
||||||
|
child: Text('Clear'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool get wantKeepAlive => true;
|
||||||
|
}
|
184
lib/widgets/debug/database.dart
Normal file
184
lib/widgets/debug/database.dart
Normal file
|
@ -0,0 +1,184 @@
|
||||||
|
import 'package:aves/model/favourite_repo.dart';
|
||||||
|
import 'package:aves/model/image_entry.dart';
|
||||||
|
import 'package:aves/model/image_metadata.dart';
|
||||||
|
import 'package:aves/model/metadata_db.dart';
|
||||||
|
import 'package:aves/utils/file_utils.dart';
|
||||||
|
import 'package:aves/widgets/common/aves_expansion_tile.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class DebugAppDatabaseSection extends StatefulWidget {
|
||||||
|
@override
|
||||||
|
_DebugAppDatabaseSectionState createState() => _DebugAppDatabaseSectionState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _DebugAppDatabaseSectionState extends State<DebugAppDatabaseSection> with AutomaticKeepAliveClientMixin {
|
||||||
|
Future<int> _dbFileSizeLoader;
|
||||||
|
Future<List<ImageEntry>> _dbEntryLoader;
|
||||||
|
Future<List<DateMetadata>> _dbDateLoader;
|
||||||
|
Future<List<CatalogMetadata>> _dbMetadataLoader;
|
||||||
|
Future<List<AddressDetails>> _dbAddressLoader;
|
||||||
|
Future<List<FavouriteRow>> _dbFavouritesLoader;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_startDbReport();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
super.build(context);
|
||||||
|
|
||||||
|
return AvesExpansionTile(
|
||||||
|
title: 'Database',
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 8),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
FutureBuilder<int>(
|
||||||
|
future: _dbFileSizeLoader,
|
||||||
|
builder: (context, snapshot) {
|
||||||
|
if (snapshot.hasError) return Text(snapshot.error.toString());
|
||||||
|
|
||||||
|
if (snapshot.connectionState != ConnectionState.done) return SizedBox.shrink();
|
||||||
|
|
||||||
|
return Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Text('DB file size: ${formatFilesize(snapshot.data)}'),
|
||||||
|
),
|
||||||
|
SizedBox(width: 8),
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: () => metadataDb.reset().then((_) => _startDbReport()),
|
||||||
|
child: Text('Reset'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
FutureBuilder<List>(
|
||||||
|
future: _dbEntryLoader,
|
||||||
|
builder: (context, snapshot) {
|
||||||
|
if (snapshot.hasError) return Text(snapshot.error.toString());
|
||||||
|
|
||||||
|
if (snapshot.connectionState != ConnectionState.done) return SizedBox.shrink();
|
||||||
|
|
||||||
|
return Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Text('entry rows: ${snapshot.data.length}'),
|
||||||
|
),
|
||||||
|
SizedBox(width: 8),
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: () => metadataDb.clearEntries().then((_) => _startDbReport()),
|
||||||
|
child: Text('Clear'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
FutureBuilder<List>(
|
||||||
|
future: _dbDateLoader,
|
||||||
|
builder: (context, snapshot) {
|
||||||
|
if (snapshot.hasError) return Text(snapshot.error.toString());
|
||||||
|
|
||||||
|
if (snapshot.connectionState != ConnectionState.done) return SizedBox.shrink();
|
||||||
|
|
||||||
|
return Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Text('date rows: ${snapshot.data.length}'),
|
||||||
|
),
|
||||||
|
SizedBox(width: 8),
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: () => metadataDb.clearDates().then((_) => _startDbReport()),
|
||||||
|
child: Text('Clear'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
FutureBuilder<List>(
|
||||||
|
future: _dbMetadataLoader,
|
||||||
|
builder: (context, snapshot) {
|
||||||
|
if (snapshot.hasError) return Text(snapshot.error.toString());
|
||||||
|
|
||||||
|
if (snapshot.connectionState != ConnectionState.done) return SizedBox.shrink();
|
||||||
|
|
||||||
|
return Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Text('metadata rows: ${snapshot.data.length}'),
|
||||||
|
),
|
||||||
|
SizedBox(width: 8),
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: () => metadataDb.clearMetadataEntries().then((_) => _startDbReport()),
|
||||||
|
child: Text('Clear'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
FutureBuilder<List>(
|
||||||
|
future: _dbAddressLoader,
|
||||||
|
builder: (context, snapshot) {
|
||||||
|
if (snapshot.hasError) return Text(snapshot.error.toString());
|
||||||
|
|
||||||
|
if (snapshot.connectionState != ConnectionState.done) return SizedBox.shrink();
|
||||||
|
|
||||||
|
return Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Text('address rows: ${snapshot.data.length}'),
|
||||||
|
),
|
||||||
|
SizedBox(width: 8),
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: () => metadataDb.clearAddresses().then((_) => _startDbReport()),
|
||||||
|
child: Text('Clear'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
FutureBuilder<List>(
|
||||||
|
future: _dbFavouritesLoader,
|
||||||
|
builder: (context, snapshot) {
|
||||||
|
if (snapshot.hasError) return Text(snapshot.error.toString());
|
||||||
|
|
||||||
|
if (snapshot.connectionState != ConnectionState.done) return SizedBox.shrink();
|
||||||
|
|
||||||
|
return Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Text('favourite rows: ${snapshot.data.length} (${favourites.count} in memory)'),
|
||||||
|
),
|
||||||
|
SizedBox(width: 8),
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: () => favourites.clear().then((_) => _startDbReport()),
|
||||||
|
child: Text('Clear'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _startDbReport() {
|
||||||
|
_dbFileSizeLoader = metadataDb.dbFileSize();
|
||||||
|
_dbEntryLoader = metadataDb.loadEntries();
|
||||||
|
_dbDateLoader = metadataDb.loadDates();
|
||||||
|
_dbMetadataLoader = metadataDb.loadMetadataEntries();
|
||||||
|
_dbAddressLoader = metadataDb.loadAddresses();
|
||||||
|
_dbFavouritesLoader = metadataDb.loadFavourites();
|
||||||
|
setState(() {});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool get wantKeepAlive => true;
|
||||||
|
}
|
43
lib/widgets/debug/firebase.dart
Normal file
43
lib/widgets/debug/firebase.dart
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
import 'package:aves/widgets/common/aves_expansion_tile.dart';
|
||||||
|
import 'package:aves/widgets/fullscreen/info/common.dart';
|
||||||
|
import 'package:firebase_analytics/firebase_analytics.dart';
|
||||||
|
import 'package:firebase_core/firebase_core.dart';
|
||||||
|
import 'package:firebase_crashlytics/firebase_crashlytics.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class DebugFirebaseSection extends StatelessWidget {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return AvesExpansionTile(
|
||||||
|
title: 'Firebase',
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 8),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: FirebaseCrashlytics.instance.crash,
|
||||||
|
child: Text('Crash'),
|
||||||
|
),
|
||||||
|
SizedBox(width: 8),
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: () => FirebaseAnalytics().logEvent(
|
||||||
|
name: 'debug_test',
|
||||||
|
parameters: {'time': DateTime.now().toIso8601String()},
|
||||||
|
),
|
||||||
|
child: Text('Send event'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.only(left: 8, right: 8, bottom: 8),
|
||||||
|
child: InfoRowGroup({
|
||||||
|
'Firebase data collection enabled': '${Firebase.app().isAutomaticDataCollectionEnabled}',
|
||||||
|
'Crashlytics collection enabled': '${FirebaseCrashlytics.instance.isCrashlyticsCollectionEnabled}',
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
40
lib/widgets/debug/settings.dart
Normal file
40
lib/widgets/debug/settings.dart
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
import 'package:aves/model/settings/settings.dart';
|
||||||
|
import 'package:aves/widgets/common/aves_expansion_tile.dart';
|
||||||
|
import 'package:aves/widgets/fullscreen/info/common.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
class DebugSettingsSection extends StatelessWidget {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Consumer<Settings>(builder: (context, settings, child) {
|
||||||
|
String toMultiline(Iterable l) => l.isNotEmpty ? '\n${l.join('\n')}' : '$l';
|
||||||
|
return AvesExpansionTile(
|
||||||
|
title: 'Settings',
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 8),
|
||||||
|
child: ElevatedButton(
|
||||||
|
onPressed: () => settings.reset(),
|
||||||
|
child: Text('Reset'),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SwitchListTile(
|
||||||
|
value: settings.hasAcceptedTerms,
|
||||||
|
onChanged: (v) => settings.hasAcceptedTerms = v,
|
||||||
|
title: Text('hasAcceptedTerms'),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.only(left: 8, right: 8, bottom: 8),
|
||||||
|
child: InfoRowGroup({
|
||||||
|
'collectionTileExtent': '${settings.collectionTileExtent}',
|
||||||
|
'infoMapZoom': '${settings.infoMapZoom}',
|
||||||
|
'pinnedFilters': toMultiline(settings.pinnedFilters),
|
||||||
|
'searchHistory': toMultiline(settings.searchHistory),
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
32
lib/widgets/debug/storage.dart
Normal file
32
lib/widgets/debug/storage.dart
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
import 'package:aves/utils/android_file_utils.dart';
|
||||||
|
import 'package:aves/widgets/common/aves_expansion_tile.dart';
|
||||||
|
import 'package:aves/widgets/fullscreen/info/common.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class DebugStorageSection extends StatelessWidget {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return AvesExpansionTile(
|
||||||
|
title: 'Storage Volumes',
|
||||||
|
children: [
|
||||||
|
...androidFileUtils.storageVolumes.expand((v) => [
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.all(8),
|
||||||
|
child: Text(v.path),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 8),
|
||||||
|
child: InfoRowGroup({
|
||||||
|
'description': '${v.description}',
|
||||||
|
'isEmulated': '${v.isEmulated}',
|
||||||
|
'isPrimary': '${v.isPrimary}',
|
||||||
|
'isRemovable': '${v.isRemovable}',
|
||||||
|
'state': '${v.state}',
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
Divider(),
|
||||||
|
])
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,9 +10,9 @@ import 'package:aves/model/source/location.dart';
|
||||||
import 'package:aves/model/source/tag.dart';
|
import 'package:aves/model/source/tag.dart';
|
||||||
import 'package:aves/utils/android_file_utils.dart';
|
import 'package:aves/utils/android_file_utils.dart';
|
||||||
import 'package:aves/widgets/about/about_page.dart';
|
import 'package:aves/widgets/about/about_page.dart';
|
||||||
import 'package:aves/widgets/app_debug_page.dart';
|
|
||||||
import 'package:aves/widgets/common/aves_logo.dart';
|
import 'package:aves/widgets/common/aves_logo.dart';
|
||||||
import 'package:aves/widgets/common/icons.dart';
|
import 'package:aves/widgets/common/icons.dart';
|
||||||
|
import 'package:aves/widgets/debug/app_debug_page.dart';
|
||||||
import 'package:aves/widgets/drawer/collection_tile.dart';
|
import 'package:aves/widgets/drawer/collection_tile.dart';
|
||||||
import 'package:aves/widgets/drawer/tile.dart';
|
import 'package:aves/widgets/drawer/tile.dart';
|
||||||
import 'package:aves/widgets/filter_grids/albums_page.dart';
|
import 'package:aves/widgets/filter_grids/albums_page.dart';
|
||||||
|
|
|
@ -60,16 +60,17 @@ class _MetadataTabState extends State<MetadataTab> {
|
||||||
}));
|
}));
|
||||||
return AvesExpansionTile(
|
return AvesExpansionTile(
|
||||||
title: title,
|
title: title,
|
||||||
children: [
|
children: data.isNotEmpty
|
||||||
Container(
|
? [
|
||||||
alignment: AlignmentDirectional.topStart,
|
Padding(
|
||||||
padding: EdgeInsets.only(left: 8, right: 8, bottom: 8),
|
padding: EdgeInsets.only(left: 8, right: 8, bottom: 8),
|
||||||
child: InfoRowGroup(
|
child: InfoRowGroup(
|
||||||
data,
|
data,
|
||||||
maxValueLength: Constants.infoGroupMaxValueLength,
|
maxValueLength: Constants.infoGroupMaxValueLength,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
],
|
]
|
||||||
|
: null,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -154,13 +154,9 @@ class _MetadataSectionSliverState extends State<MetadataSectionSliver> with Auto
|
||||||
expandedNotifier: _expandedDirectoryNotifier,
|
expandedNotifier: _expandedDirectoryNotifier,
|
||||||
children: [
|
children: [
|
||||||
if (prefixChildren.isNotEmpty)
|
if (prefixChildren.isNotEmpty)
|
||||||
Align(
|
Wrap(children: prefixChildren),
|
||||||
alignment: AlignmentDirectional.topStart,
|
|
||||||
child: Wrap(children: prefixChildren),
|
|
||||||
),
|
|
||||||
if (thumbnail != null) thumbnail,
|
if (thumbnail != null) thumbnail,
|
||||||
Container(
|
Padding(
|
||||||
alignment: Alignment.topLeft,
|
|
||||||
padding: EdgeInsets.only(left: 8, right: 8, bottom: 8),
|
padding: EdgeInsets.only(left: 8, right: 8, bottom: 8),
|
||||||
child: InfoRowGroup(dir.tags, maxValueLength: Constants.infoGroupMaxValueLength),
|
child: InfoRowGroup(dir.tags, maxValueLength: Constants.infoGroupMaxValueLength),
|
||||||
),
|
),
|
||||||
|
|
|
@ -27,8 +27,6 @@ class _SettingsPageState extends State<SettingsPage> {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return MediaQueryDataProvider(
|
return MediaQueryDataProvider(
|
||||||
child: DefaultTabController(
|
|
||||||
length: 4,
|
|
||||||
child: Scaffold(
|
child: Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text('Settings'),
|
title: Text('Settings'),
|
||||||
|
@ -61,7 +59,6 @@ class _SettingsPageState extends State<SettingsPage> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -220,9 +217,8 @@ class _SettingsPageState extends State<SettingsPage> {
|
||||||
onChanged: (v) => settings.isCrashlyticsEnabled = v,
|
onChanged: (v) => settings.isCrashlyticsEnabled = v,
|
||||||
title: Text('Allow anonymous analytics and crash reporting'),
|
title: Text('Allow anonymous analytics and crash reporting'),
|
||||||
),
|
),
|
||||||
Container(
|
Padding(
|
||||||
alignment: AlignmentDirectional.topStart,
|
padding: EdgeInsets.only(top: 8, bottom: 16),
|
||||||
padding: EdgeInsets.only(bottom: 16),
|
|
||||||
child: GrantedDirectories(),
|
child: GrantedDirectories(),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
|
@ -169,7 +169,7 @@ packages:
|
||||||
description:
|
description:
|
||||||
path: "."
|
path: "."
|
||||||
ref: HEAD
|
ref: HEAD
|
||||||
resolved-ref: edb6b11bb448fc2f30e566a20605b37093503176
|
resolved-ref: "51fe2b12588356fade82ce65daef5482beed54e7"
|
||||||
url: "git://github.com/deckerst/expansion_tile_card.git"
|
url: "git://github.com/deckerst/expansion_tile_card.git"
|
||||||
source: git
|
source: git
|
||||||
version: "1.0.3"
|
version: "1.0.3"
|
||||||
|
|
Loading…
Reference in a new issue