minor fixes
This commit is contained in:
parent
abca3644f5
commit
1ef9d75b0b
10 changed files with 101 additions and 48 deletions
|
@ -22,7 +22,7 @@ import 'package:fijkplayer/fijkplayer.dart';
|
|||
import 'package:flutter/foundation.dart';
|
||||
|
||||
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 = {
|
||||
RegExp(r'^\d{2}[-/]\d{2}[-/]\d{4}$'),
|
||||
};
|
||||
|
@ -127,6 +127,7 @@ class VideoMetadataFormatter {
|
|||
// - `2022-01-28T5:07:46 p. m.Z`
|
||||
// - `2012-1-1T12:00:00Z`
|
||||
// - `2020.10.14`
|
||||
// - `2016:11:16 18:00:00`
|
||||
// - `2021` (not enough to build a date)
|
||||
|
||||
var match = _dateY4M2D2H2m2s2Pattern.firstMatch(dateString);
|
||||
|
|
|
@ -165,6 +165,7 @@ class _CollectionAppBarState extends State<CollectionAppBar> with SingleTickerPr
|
|||
builder: (context, _, child) {
|
||||
final isTelevision = device.isTelevision;
|
||||
final actions = _buildActions(context, selection);
|
||||
final onFilterTap = removableFilters ? collection.removeFilter : null;
|
||||
return AvesAppBar(
|
||||
contentHeight: appBarContentHeight,
|
||||
leading: _buildAppBarLeading(
|
||||
|
@ -192,8 +193,8 @@ class _CollectionAppBarState extends State<CollectionAppBar> with SingleTickerPr
|
|||
},
|
||||
child: FilterBar(
|
||||
filters: visibleFilters,
|
||||
removable: removableFilters,
|
||||
onTap: removableFilters ? collection.removeFilter : null,
|
||||
onTap: onFilterTap,
|
||||
onRemove: onFilterTap,
|
||||
),
|
||||
),
|
||||
if (queryEnabled)
|
||||
|
|
|
@ -11,14 +11,13 @@ class FilterBar extends StatefulWidget {
|
|||
static const double preferredHeight = AvesFilterChip.minChipHeight + verticalPadding;
|
||||
|
||||
final List<CollectionFilter> filters;
|
||||
final bool removable;
|
||||
final FilterCallback? onTap;
|
||||
final FilterCallback? onTap, onRemove;
|
||||
|
||||
FilterBar({
|
||||
super.key,
|
||||
required Set<CollectionFilter> filters,
|
||||
this.removable = false,
|
||||
this.onTap,
|
||||
this.onRemove,
|
||||
}) : filters = List<CollectionFilter>.from(filters)..sort();
|
||||
|
||||
@override
|
||||
|
@ -31,8 +30,6 @@ class _FilterBarState extends State<FilterBar> {
|
|||
|
||||
List<CollectionFilter> get filters => widget.filters;
|
||||
|
||||
FilterCallback? get onTap => widget.onTap;
|
||||
|
||||
@override
|
||||
void didUpdateWidget(covariant FilterBar oldWidget) {
|
||||
super.didUpdateWidget(oldWidget);
|
||||
|
@ -104,30 +101,37 @@ class _FilterBarState extends State<FilterBar> {
|
|||
}
|
||||
|
||||
Widget _buildChip(CollectionFilter filter) {
|
||||
final onTap = widget.onTap != null
|
||||
? (filter) {
|
||||
_userTappedFilter = filter;
|
||||
widget.onTap?.call(filter);
|
||||
}
|
||||
: null;
|
||||
final onRemove = widget.onRemove != null
|
||||
? (filter) {
|
||||
_userTappedFilter = filter;
|
||||
widget.onRemove?.call(filter);
|
||||
}
|
||||
: null;
|
||||
return _Chip(
|
||||
filter: filter,
|
||||
removable: widget.removable,
|
||||
single: filters.length == 1,
|
||||
onTap: onTap != null
|
||||
? (filter) {
|
||||
_userTappedFilter = filter;
|
||||
onTap!(filter);
|
||||
}
|
||||
: null,
|
||||
onTap: onTap,
|
||||
onRemove: onRemove,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _Chip extends StatelessWidget {
|
||||
final CollectionFilter filter;
|
||||
final bool removable, single;
|
||||
final FilterCallback? onTap;
|
||||
final bool single;
|
||||
final FilterCallback? onTap, onRemove;
|
||||
|
||||
const _Chip({
|
||||
required this.filter,
|
||||
required this.removable,
|
||||
required this.single,
|
||||
required this.onTap,
|
||||
required this.onRemove,
|
||||
});
|
||||
|
||||
@override
|
||||
|
@ -138,7 +142,6 @@ class _Chip extends StatelessWidget {
|
|||
child: AvesFilterChip(
|
||||
key: ValueKey(filter),
|
||||
filter: filter,
|
||||
removable: removable,
|
||||
maxWidth: single
|
||||
? AvesFilterChip.computeMaxWidth(
|
||||
context,
|
||||
|
@ -149,6 +152,7 @@ class _Chip extends StatelessWidget {
|
|||
: null,
|
||||
heroType: HeroType.always,
|
||||
onTap: onTap,
|
||||
onRemove: onRemove,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
|
|
@ -67,10 +67,11 @@ class TitledExpandableFilterRow extends StatelessWidget {
|
|||
class ExpandableFilterRow extends StatelessWidget {
|
||||
final List<CollectionFilter> filters;
|
||||
final bool isExpanded;
|
||||
final bool removable, showGenericIcon;
|
||||
final bool showGenericIcon;
|
||||
final Widget? Function(CollectionFilter)? leadingBuilder;
|
||||
final HeroType Function(CollectionFilter filter)? heroTypeBuilder;
|
||||
final FilterCallback onTap;
|
||||
final FilterCallback? onRemove;
|
||||
final OffsetFilterCallback? onLongPress;
|
||||
|
||||
static const double horizontalPadding = 8;
|
||||
|
@ -80,11 +81,11 @@ class ExpandableFilterRow extends StatelessWidget {
|
|||
super.key,
|
||||
required this.filters,
|
||||
required this.isExpanded,
|
||||
this.removable = false,
|
||||
this.showGenericIcon = true,
|
||||
this.leadingBuilder,
|
||||
this.heroTypeBuilder,
|
||||
required this.onTap,
|
||||
this.onRemove,
|
||||
required this.onLongPress,
|
||||
});
|
||||
|
||||
|
@ -143,11 +144,11 @@ class ExpandableFilterRow extends StatelessWidget {
|
|||
// key `album-{path}` is expected by test driver
|
||||
key: Key(filter.key),
|
||||
filter: filter,
|
||||
removable: removable,
|
||||
showGenericIcon: showGenericIcon,
|
||||
leadingOverride: leadingBuilder?.call(filter),
|
||||
heroType: heroTypeBuilder?.call(filter) ?? HeroType.onTap,
|
||||
onTap: onTap,
|
||||
onRemove: onRemove,
|
||||
onLongPress: onLongPress,
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import 'package:aves/model/device.dart';
|
||||
import 'package:aves/model/settings/settings.dart';
|
||||
import 'package:aves/theme/colors.dart';
|
||||
import 'package:aves/theme/durations.dart';
|
||||
import 'package:aves/widgets/aves_app.dart';
|
||||
import 'package:aves/widgets/common/fx/blurred.dart';
|
||||
|
@ -63,7 +64,7 @@ class AvesAppBar extends StatelessWidget {
|
|||
: const SizedBox(width: 16),
|
||||
Expanded(
|
||||
child: DefaultTextStyle(
|
||||
style: Theme.of(context).appBarTheme.titleTextStyle!,
|
||||
style: context.select<AvesColorsData, TextStyle>((v) => Theme.of(context).appBarTheme.titleTextStyle!),
|
||||
child: Hero(
|
||||
tag: titleHeroTag,
|
||||
flightShuttleBuilder: _flightShuttleBuilder,
|
||||
|
|
|
@ -44,14 +44,14 @@ class AvesFilterDecoration {
|
|||
|
||||
class AvesFilterChip extends StatefulWidget {
|
||||
final CollectionFilter filter;
|
||||
final bool removable, showText, showGenericIcon, useFilterColor;
|
||||
final bool showText, showGenericIcon, useFilterColor;
|
||||
final AvesFilterDecoration? decoration;
|
||||
final String? banner;
|
||||
final Widget? leadingOverride, details;
|
||||
final double padding;
|
||||
final double? maxWidth;
|
||||
final HeroType heroType;
|
||||
final FilterCallback? onTap;
|
||||
final FilterCallback? onTap, onRemove;
|
||||
final OffsetFilterCallback? onLongPress;
|
||||
|
||||
static const double defaultRadius = 32;
|
||||
|
@ -65,7 +65,6 @@ class AvesFilterChip extends StatefulWidget {
|
|||
const AvesFilterChip({
|
||||
super.key,
|
||||
required this.filter,
|
||||
this.removable = false,
|
||||
this.showText = true,
|
||||
this.showGenericIcon = true,
|
||||
this.useFilterColor = true,
|
||||
|
@ -77,6 +76,7 @@ class AvesFilterChip extends StatefulWidget {
|
|||
this.maxWidth,
|
||||
this.heroType = HeroType.onTap,
|
||||
this.onTap,
|
||||
this.onRemove,
|
||||
this.onLongPress = showDefaultLongPressMenu,
|
||||
});
|
||||
|
||||
|
@ -154,10 +154,6 @@ class _AvesFilterChipState extends State<AvesFilterChip> {
|
|||
|
||||
double get padding => widget.padding;
|
||||
|
||||
FilterCallback? get onTap => widget.onTap;
|
||||
|
||||
OffsetFilterCallback? get onLongPress => widget.onLongPress;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
@ -219,12 +215,40 @@ class _AvesFilterChipState extends State<AvesFilterChip> {
|
|||
final decoration = widget.decoration;
|
||||
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;
|
||||
if (widget.showText) {
|
||||
final textScaleFactor = MediaQuery.textScaleFactorOf(context);
|
||||
final iconSize = AvesFilterChip.iconSize * textScaleFactor;
|
||||
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(
|
||||
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`,
|
||||
// so we get the long press details from the tap instead
|
||||
onTapDown: onLongPress != null ? (details) => _tapPosition = details.globalPosition : null,
|
||||
onTap: onTap != null
|
||||
? () {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) => onTap!(filter));
|
||||
setState(() => _tapped = true);
|
||||
}
|
||||
: null,
|
||||
onLongPress: onLongPress != null ? () => onLongPress!(context, filter, _tapPosition!) : null,
|
||||
onTap: onTap,
|
||||
onLongPress: onLongPress,
|
||||
borderRadius: borderRadius,
|
||||
child: FutureBuilder<Color>(
|
||||
future: _colorFuture,
|
||||
|
|
|
@ -150,14 +150,16 @@ class _TagEditorPageState extends State<TagEditorPage> {
|
|||
secondChild: ExpandableFilterRow(
|
||||
filters: sortedTags.map((kv) => kv.key).toList(),
|
||||
isExpanded: context.select<Settings, bool>((v) => v.tagEditorCurrentFilterSectionExpanded),
|
||||
removable: true,
|
||||
showGenericIcon: false,
|
||||
leadingBuilder: showCount
|
||||
? (filter) => _TagCount(
|
||||
count: sortedTags.firstWhere((kv) => kv.key == filter).value,
|
||||
)
|
||||
: null,
|
||||
onTap: _removeTag,
|
||||
onTap: (filter) {
|
||||
// TODO TLAD [#453]
|
||||
},
|
||||
onRemove: _removeTag,
|
||||
onLongPress: null,
|
||||
),
|
||||
crossFadeState: sortedTags.isEmpty ? CrossFadeState.showFirst : CrossFadeState.showSecond,
|
||||
|
|
|
@ -88,14 +88,15 @@ class _HiddenFilters extends StatelessWidget {
|
|||
child: Wrap(
|
||||
spacing: 8,
|
||||
runSpacing: 8,
|
||||
children: filterList
|
||||
.map((filter) => AvesFilterChip(
|
||||
filter: filter,
|
||||
removable: true,
|
||||
onTap: (filter) => settings.changeFilterVisibility({filter}, true),
|
||||
onLongPress: null,
|
||||
))
|
||||
.toList(),
|
||||
children: filterList.map((filter) {
|
||||
void onRemove(CollectionFilter filter) => settings.changeFilterVisibility({filter}, true);
|
||||
return AvesFilterChip(
|
||||
filter: filter,
|
||||
onTap: onRemove,
|
||||
onRemove: onRemove,
|
||||
onLongPress: null,
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
),
|
||||
],
|
||||
|
|
22
scripts/extract_apks.sh
Executable file
22
scripts/extract_apks.sh
Executable 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"
|
|
@ -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('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('2016:11:16 18:00:00'), DateTime(2016, 11, 16, 18, 0, 0).millisecondsSinceEpoch);
|
||||
});
|
||||
|
||||
test('Ambiguous date', () {
|
||||
|
|
Loading…
Reference in a new issue