minor fixes

This commit is contained in:
Thibault Deckers 2022-12-21 18:26:44 +01:00
parent abca3644f5
commit 1ef9d75b0b
10 changed files with 101 additions and 48 deletions

View file

@ -22,7 +22,7 @@ import 'package:fijkplayer/fijkplayer.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
class VideoMetadataFormatter { class VideoMetadataFormatter {
static final _dateY4M2D2H2m2s2Pattern = RegExp(r'(\d{4})[-./](\d{1,2})[-./](\d{1,2})([ T](\d{1,2}):(\d{1,2}):(\d{1,2})( ([ap]\.? ?m\.?))?)?'); static final _dateY4M2D2H2m2s2Pattern = RegExp(r'(\d{4})[-./:](\d{1,2})[-./:](\d{1,2})([ T](\d{1,2}):(\d{1,2}):(\d{1,2})( ([ap]\.? ?m\.?))?)?');
static final _ambiguousDatePatterns = { static final _ambiguousDatePatterns = {
RegExp(r'^\d{2}[-/]\d{2}[-/]\d{4}$'), RegExp(r'^\d{2}[-/]\d{2}[-/]\d{4}$'),
}; };
@ -127,6 +127,7 @@ class VideoMetadataFormatter {
// - `2022-01-28T5:07:46 p. m.Z` // - `2022-01-28T5:07:46 p. m.Z`
// - `2012-1-1T12:00:00Z` // - `2012-1-1T12:00:00Z`
// - `2020.10.14` // - `2020.10.14`
// - `2016:11:16 18:00:00`
// - `2021` (not enough to build a date) // - `2021` (not enough to build a date)
var match = _dateY4M2D2H2m2s2Pattern.firstMatch(dateString); var match = _dateY4M2D2H2m2s2Pattern.firstMatch(dateString);

View file

@ -165,6 +165,7 @@ class _CollectionAppBarState extends State<CollectionAppBar> with SingleTickerPr
builder: (context, _, child) { builder: (context, _, child) {
final isTelevision = device.isTelevision; final isTelevision = device.isTelevision;
final actions = _buildActions(context, selection); final actions = _buildActions(context, selection);
final onFilterTap = removableFilters ? collection.removeFilter : null;
return AvesAppBar( return AvesAppBar(
contentHeight: appBarContentHeight, contentHeight: appBarContentHeight,
leading: _buildAppBarLeading( leading: _buildAppBarLeading(
@ -192,8 +193,8 @@ class _CollectionAppBarState extends State<CollectionAppBar> with SingleTickerPr
}, },
child: FilterBar( child: FilterBar(
filters: visibleFilters, filters: visibleFilters,
removable: removableFilters, onTap: onFilterTap,
onTap: removableFilters ? collection.removeFilter : null, onRemove: onFilterTap,
), ),
), ),
if (queryEnabled) if (queryEnabled)

View file

@ -11,14 +11,13 @@ class FilterBar extends StatefulWidget {
static const double preferredHeight = AvesFilterChip.minChipHeight + verticalPadding; static const double preferredHeight = AvesFilterChip.minChipHeight + verticalPadding;
final List<CollectionFilter> filters; final List<CollectionFilter> filters;
final bool removable; final FilterCallback? onTap, onRemove;
final FilterCallback? onTap;
FilterBar({ FilterBar({
super.key, super.key,
required Set<CollectionFilter> filters, required Set<CollectionFilter> filters,
this.removable = false,
this.onTap, this.onTap,
this.onRemove,
}) : filters = List<CollectionFilter>.from(filters)..sort(); }) : filters = List<CollectionFilter>.from(filters)..sort();
@override @override
@ -31,8 +30,6 @@ class _FilterBarState extends State<FilterBar> {
List<CollectionFilter> get filters => widget.filters; List<CollectionFilter> get filters => widget.filters;
FilterCallback? get onTap => widget.onTap;
@override @override
void didUpdateWidget(covariant FilterBar oldWidget) { void didUpdateWidget(covariant FilterBar oldWidget) {
super.didUpdateWidget(oldWidget); super.didUpdateWidget(oldWidget);
@ -104,30 +101,37 @@ class _FilterBarState extends State<FilterBar> {
} }
Widget _buildChip(CollectionFilter filter) { Widget _buildChip(CollectionFilter filter) {
return _Chip( final onTap = widget.onTap != null
filter: filter,
removable: widget.removable,
single: filters.length == 1,
onTap: onTap != null
? (filter) { ? (filter) {
_userTappedFilter = filter; _userTappedFilter = filter;
onTap!(filter); widget.onTap?.call(filter);
} }
: null, : null;
final onRemove = widget.onRemove != null
? (filter) {
_userTappedFilter = filter;
widget.onRemove?.call(filter);
}
: null;
return _Chip(
filter: filter,
single: filters.length == 1,
onTap: onTap,
onRemove: onRemove,
); );
} }
} }
class _Chip extends StatelessWidget { class _Chip extends StatelessWidget {
final CollectionFilter filter; final CollectionFilter filter;
final bool removable, single; final bool single;
final FilterCallback? onTap; final FilterCallback? onTap, onRemove;
const _Chip({ const _Chip({
required this.filter, required this.filter,
required this.removable,
required this.single, required this.single,
required this.onTap, required this.onTap,
required this.onRemove,
}); });
@override @override
@ -138,7 +142,6 @@ class _Chip extends StatelessWidget {
child: AvesFilterChip( child: AvesFilterChip(
key: ValueKey(filter), key: ValueKey(filter),
filter: filter, filter: filter,
removable: removable,
maxWidth: single maxWidth: single
? AvesFilterChip.computeMaxWidth( ? AvesFilterChip.computeMaxWidth(
context, context,
@ -149,6 +152,7 @@ class _Chip extends StatelessWidget {
: null, : null,
heroType: HeroType.always, heroType: HeroType.always,
onTap: onTap, onTap: onTap,
onRemove: onRemove,
), ),
), ),
); );

View file

@ -67,10 +67,11 @@ class TitledExpandableFilterRow extends StatelessWidget {
class ExpandableFilterRow extends StatelessWidget { class ExpandableFilterRow extends StatelessWidget {
final List<CollectionFilter> filters; final List<CollectionFilter> filters;
final bool isExpanded; final bool isExpanded;
final bool removable, showGenericIcon; final bool showGenericIcon;
final Widget? Function(CollectionFilter)? leadingBuilder; final Widget? Function(CollectionFilter)? leadingBuilder;
final HeroType Function(CollectionFilter filter)? heroTypeBuilder; final HeroType Function(CollectionFilter filter)? heroTypeBuilder;
final FilterCallback onTap; final FilterCallback onTap;
final FilterCallback? onRemove;
final OffsetFilterCallback? onLongPress; final OffsetFilterCallback? onLongPress;
static const double horizontalPadding = 8; static const double horizontalPadding = 8;
@ -80,11 +81,11 @@ class ExpandableFilterRow extends StatelessWidget {
super.key, super.key,
required this.filters, required this.filters,
required this.isExpanded, required this.isExpanded,
this.removable = false,
this.showGenericIcon = true, this.showGenericIcon = true,
this.leadingBuilder, this.leadingBuilder,
this.heroTypeBuilder, this.heroTypeBuilder,
required this.onTap, required this.onTap,
this.onRemove,
required this.onLongPress, required this.onLongPress,
}); });
@ -143,11 +144,11 @@ class ExpandableFilterRow extends StatelessWidget {
// key `album-{path}` is expected by test driver // key `album-{path}` is expected by test driver
key: Key(filter.key), key: Key(filter.key),
filter: filter, filter: filter,
removable: removable,
showGenericIcon: showGenericIcon, showGenericIcon: showGenericIcon,
leadingOverride: leadingBuilder?.call(filter), leadingOverride: leadingBuilder?.call(filter),
heroType: heroTypeBuilder?.call(filter) ?? HeroType.onTap, heroType: heroTypeBuilder?.call(filter) ?? HeroType.onTap,
onTap: onTap, onTap: onTap,
onRemove: onRemove,
onLongPress: onLongPress, onLongPress: onLongPress,
); );
} }

View file

@ -1,5 +1,6 @@
import 'package:aves/model/device.dart'; import 'package:aves/model/device.dart';
import 'package:aves/model/settings/settings.dart'; import 'package:aves/model/settings/settings.dart';
import 'package:aves/theme/colors.dart';
import 'package:aves/theme/durations.dart'; import 'package:aves/theme/durations.dart';
import 'package:aves/widgets/aves_app.dart'; import 'package:aves/widgets/aves_app.dart';
import 'package:aves/widgets/common/fx/blurred.dart'; import 'package:aves/widgets/common/fx/blurred.dart';
@ -63,7 +64,7 @@ class AvesAppBar extends StatelessWidget {
: const SizedBox(width: 16), : const SizedBox(width: 16),
Expanded( Expanded(
child: DefaultTextStyle( child: DefaultTextStyle(
style: Theme.of(context).appBarTheme.titleTextStyle!, style: context.select<AvesColorsData, TextStyle>((v) => Theme.of(context).appBarTheme.titleTextStyle!),
child: Hero( child: Hero(
tag: titleHeroTag, tag: titleHeroTag,
flightShuttleBuilder: _flightShuttleBuilder, flightShuttleBuilder: _flightShuttleBuilder,

View file

@ -44,14 +44,14 @@ class AvesFilterDecoration {
class AvesFilterChip extends StatefulWidget { class AvesFilterChip extends StatefulWidget {
final CollectionFilter filter; final CollectionFilter filter;
final bool removable, showText, showGenericIcon, useFilterColor; final bool showText, showGenericIcon, useFilterColor;
final AvesFilterDecoration? decoration; final AvesFilterDecoration? decoration;
final String? banner; final String? banner;
final Widget? leadingOverride, details; final Widget? leadingOverride, details;
final double padding; final double padding;
final double? maxWidth; final double? maxWidth;
final HeroType heroType; final HeroType heroType;
final FilterCallback? onTap; final FilterCallback? onTap, onRemove;
final OffsetFilterCallback? onLongPress; final OffsetFilterCallback? onLongPress;
static const double defaultRadius = 32; static const double defaultRadius = 32;
@ -65,7 +65,6 @@ class AvesFilterChip extends StatefulWidget {
const AvesFilterChip({ const AvesFilterChip({
super.key, super.key,
required this.filter, required this.filter,
this.removable = false,
this.showText = true, this.showText = true,
this.showGenericIcon = true, this.showGenericIcon = true,
this.useFilterColor = true, this.useFilterColor = true,
@ -77,6 +76,7 @@ class AvesFilterChip extends StatefulWidget {
this.maxWidth, this.maxWidth,
this.heroType = HeroType.onTap, this.heroType = HeroType.onTap,
this.onTap, this.onTap,
this.onRemove,
this.onLongPress = showDefaultLongPressMenu, this.onLongPress = showDefaultLongPressMenu,
}); });
@ -154,10 +154,6 @@ class _AvesFilterChipState extends State<AvesFilterChip> {
double get padding => widget.padding; double get padding => widget.padding;
FilterCallback? get onTap => widget.onTap;
OffsetFilterCallback? get onLongPress => widget.onLongPress;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
@ -219,12 +215,40 @@ class _AvesFilterChipState extends State<AvesFilterChip> {
final decoration = widget.decoration; final decoration = widget.decoration;
final chipBackground = Theme.of(context).scaffoldBackgroundColor; final chipBackground = Theme.of(context).scaffoldBackgroundColor;
final onTap = widget.onTap != null
? () {
WidgetsBinding.instance.addPostFrameCallback((_) => widget.onTap?.call(filter));
setState(() => _tapped = true);
}
: null;
final onRemove = widget.onRemove != null
? () {
WidgetsBinding.instance.addPostFrameCallback((_) => widget.onRemove?.call(filter));
setState(() => _tapped = true);
}
: null;
final onLongPress = widget.onLongPress != null
? () {
if (_tapPosition != null) {
widget.onLongPress?.call(context, filter, _tapPosition!);
}
}
: null;
Widget? content; Widget? content;
if (widget.showText) { if (widget.showText) {
final textScaleFactor = MediaQuery.textScaleFactorOf(context); final textScaleFactor = MediaQuery.textScaleFactorOf(context);
final iconSize = AvesFilterChip.iconSize * textScaleFactor; final iconSize = AvesFilterChip.iconSize * textScaleFactor;
final leading = widget.leadingOverride ?? filter.iconBuilder(context, iconSize, showGenericIcon: widget.showGenericIcon); final leading = widget.leadingOverride ?? filter.iconBuilder(context, iconSize, showGenericIcon: widget.showGenericIcon);
final trailing = widget.removable ? Icon(AIcons.clear, size: iconSize) : null; final trailing = onRemove != null
? IconButton(
icon: Icon(AIcons.clear, size: iconSize),
padding: EdgeInsets.zero,
splashRadius: IconTheme.of(context).size,
constraints: const BoxConstraints(),
onPressed: onRemove,
)
: null;
content = Row( content = Row(
mainAxisSize: decoration != null ? MainAxisSize.max : MainAxisSize.min, mainAxisSize: decoration != null ? MainAxisSize.max : MainAxisSize.min,
@ -317,13 +341,8 @@ class _AvesFilterChipState extends State<AvesFilterChip> {
// as of Flutter v2.8.0, `InkWell` does not have `onLongPressStart` like `GestureDetector`, // as of Flutter v2.8.0, `InkWell` does not have `onLongPressStart` like `GestureDetector`,
// so we get the long press details from the tap instead // so we get the long press details from the tap instead
onTapDown: onLongPress != null ? (details) => _tapPosition = details.globalPosition : null, onTapDown: onLongPress != null ? (details) => _tapPosition = details.globalPosition : null,
onTap: onTap != null onTap: onTap,
? () { onLongPress: onLongPress,
WidgetsBinding.instance.addPostFrameCallback((_) => onTap!(filter));
setState(() => _tapped = true);
}
: null,
onLongPress: onLongPress != null ? () => onLongPress!(context, filter, _tapPosition!) : null,
borderRadius: borderRadius, borderRadius: borderRadius,
child: FutureBuilder<Color>( child: FutureBuilder<Color>(
future: _colorFuture, future: _colorFuture,

View file

@ -150,14 +150,16 @@ class _TagEditorPageState extends State<TagEditorPage> {
secondChild: ExpandableFilterRow( secondChild: ExpandableFilterRow(
filters: sortedTags.map((kv) => kv.key).toList(), filters: sortedTags.map((kv) => kv.key).toList(),
isExpanded: context.select<Settings, bool>((v) => v.tagEditorCurrentFilterSectionExpanded), isExpanded: context.select<Settings, bool>((v) => v.tagEditorCurrentFilterSectionExpanded),
removable: true,
showGenericIcon: false, showGenericIcon: false,
leadingBuilder: showCount leadingBuilder: showCount
? (filter) => _TagCount( ? (filter) => _TagCount(
count: sortedTags.firstWhere((kv) => kv.key == filter).value, count: sortedTags.firstWhere((kv) => kv.key == filter).value,
) )
: null, : null,
onTap: _removeTag, onTap: (filter) {
// TODO TLAD [#453]
},
onRemove: _removeTag,
onLongPress: null, onLongPress: null,
), ),
crossFadeState: sortedTags.isEmpty ? CrossFadeState.showFirst : CrossFadeState.showSecond, crossFadeState: sortedTags.isEmpty ? CrossFadeState.showFirst : CrossFadeState.showSecond,

View file

@ -88,14 +88,15 @@ class _HiddenFilters extends StatelessWidget {
child: Wrap( child: Wrap(
spacing: 8, spacing: 8,
runSpacing: 8, runSpacing: 8,
children: filterList children: filterList.map((filter) {
.map((filter) => AvesFilterChip( void onRemove(CollectionFilter filter) => settings.changeFilterVisibility({filter}, true);
return AvesFilterChip(
filter: filter, filter: filter,
removable: true, onTap: onRemove,
onTap: (filter) => settings.changeFilterVisibility({filter}, true), onRemove: onRemove,
onLongPress: null, onLongPress: null,
)) );
.toList(), }).toList(),
), ),
), ),
], ],

22
scripts/extract_apks.sh Executable file
View file

@ -0,0 +1,22 @@
#!/bin/bash
if [ ! -d "scripts" ]; then
cd ..
fi
BUNDLE="/home/tibo/Downloads/app-play-release.aab"
# shellcheck disable=SC2001
OUTPUT=$(sed "s|\.aab|\.apks|" <<<"$BUNDLE")
KEYS_PATH="android/key.properties"
STORE_PATH=$(sed -n 's|.*storeFile=\(.*\)[\r\n]|\1|p' "$KEYS_PATH")
# shellcheck disable=SC1003
STORE_PW=$(sed -n 's|.*storePassword=\(.*\)[\r\n]|\1|p' "$KEYS_PATH" | sed 's|\\'\''|'\''|g')
KEY_ALIAS=$(sed -n 's|.*keyAlias=\(.*\)[\r\n]|\1|p' "$KEYS_PATH")
# shellcheck disable=SC1003
KEY_PW=$(sed -n 's|.*keyPassword=\(.*\)[\r\n]|\1|p' "$KEYS_PATH" | sed 's|\\'\''|'\''|g')
echo "$BUNDLE -> $OUTPUT"
bundletool build-apks --bundle="$BUNDLE" --output="$OUTPUT" \
--ks="$STORE_PATH" --ks-pass="pass:$STORE_PW" \
--ks-key-alias="$KEY_ALIAS" --key-pass="pass:$KEY_PW"

View file

@ -16,6 +16,7 @@ void main() {
expect(VideoMetadataFormatter.parseVideoDate('2022-01-28T5:07:46 p. m.Z'), DateTime(2022, 1, 28, 17, 7, 46).millisecondsSinceEpoch); expect(VideoMetadataFormatter.parseVideoDate('2022-01-28T5:07:46 p. m.Z'), DateTime(2022, 1, 28, 17, 7, 46).millisecondsSinceEpoch);
expect(VideoMetadataFormatter.parseVideoDate('2012-1-1T12:00:00Z'), DateTime(2012, 1, 1, 12, 0, 0).millisecondsSinceEpoch); expect(VideoMetadataFormatter.parseVideoDate('2012-1-1T12:00:00Z'), DateTime(2012, 1, 1, 12, 0, 0).millisecondsSinceEpoch);
expect(VideoMetadataFormatter.parseVideoDate('2020.10.14'), DateTime(2020, 10, 14).millisecondsSinceEpoch); expect(VideoMetadataFormatter.parseVideoDate('2020.10.14'), DateTime(2020, 10, 14).millisecondsSinceEpoch);
expect(VideoMetadataFormatter.parseVideoDate('2016:11:16 18:00:00'), DateTime(2016, 11, 16, 18, 0, 0).millisecondsSinceEpoch);
}); });
test('Ambiguous date', () { test('Ambiguous date', () {