#265 search: by field (id year month day width height size)

This commit is contained in:
Thibault Deckers 2022-06-18 15:14:42 +09:00
parent 924b771cbc
commit 9bced31927
2 changed files with 133 additions and 27 deletions

View file

@ -2,6 +2,7 @@ import 'package:aves/model/entry.dart';
import 'package:aves/model/filters/filters.dart';
import 'package:aves/theme/colors.dart';
import 'package:aves/theme/icons.dart';
import 'package:aves/utils/file_utils.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
@ -20,30 +21,25 @@ class QueryFilter extends CollectionFilter {
List<Object?> get props => [query, live];
static final _fieldPattern = RegExp(r'(.+)([=<>])(.+)');
static final _fileSizePattern = RegExp(r'(\d+)([KMG])?');
static const keyContentId = 'ID';
static const keyContentYear = 'YEAR';
static const keyContentMonth = 'MONTH';
static const keyContentDay = 'DAY';
static const keyContentWidth = 'WIDTH';
static const keyContentHeight = 'HEIGHT';
static const keyContentSize = 'SIZE';
static const opEqual = '=';
static const opLower = '<';
static const opGreater = '>';
QueryFilter(this.query, {this.colorful = true, this.live = false}) {
var upQuery = query.toUpperCase();
final match = _fieldPattern.firstMatch(upQuery);
if (match != null) {
final key = match.group(1)?.trim();
final op = match.group(2)?.trim();
final value = match.group(3)?.trim();
if (key != null && op != null && value != null) {
switch (key) {
case keyContentId:
if (op == opEqual) {
final contentId = int.tryParse(value);
if (contentId != null) {
_test = (entry) => entry.contentId == contentId;
return;
}
}
break;
}
}
final test = fieldTest(upQuery);
if (test != null) {
_test = test;
return;
}
// allow NOT queries starting with `-`
@ -101,4 +97,114 @@ class QueryFilter extends CollectionFilter {
@override
String get key => '$type-$query';
EntryFilter? fieldTest(String upQuery) {
var match = _fieldPattern.firstMatch(upQuery);
if (match == null) return null;
final key = match.group(1)?.trim();
final op = match.group(2)?.trim();
var valueString = match.group(3)?.trim();
if (key == null || op == null || valueString == null) return null;
final valueInt = int.tryParse(valueString);
switch (key) {
case keyContentId:
if (valueInt == null) return null;
if (op == opEqual) {
return (entry) => entry.contentId == valueInt;
}
break;
case keyContentYear:
if (valueInt == null) return null;
switch (op) {
case opEqual:
return (entry) => (entry.bestDate?.year ?? 0) == valueInt;
case opLower:
return (entry) => (entry.bestDate?.year ?? 0) < valueInt;
case opGreater:
return (entry) => (entry.bestDate?.year ?? 0) > valueInt;
}
break;
case keyContentMonth:
if (valueInt == null) return null;
switch (op) {
case opEqual:
return (entry) => (entry.bestDate?.month ?? 0) == valueInt;
case opLower:
return (entry) => (entry.bestDate?.month ?? 0) < valueInt;
case opGreater:
return (entry) => (entry.bestDate?.month ?? 0) > valueInt;
}
break;
case keyContentDay:
if (valueInt == null) return null;
switch (op) {
case opEqual:
return (entry) => (entry.bestDate?.day ?? 0) == valueInt;
case opLower:
return (entry) => (entry.bestDate?.day ?? 0) < valueInt;
case opGreater:
return (entry) => (entry.bestDate?.day ?? 0) > valueInt;
}
break;
case keyContentWidth:
if (valueInt == null) return null;
switch (op) {
case opEqual:
return (entry) => entry.displaySize.width == valueInt;
case opLower:
return (entry) => entry.displaySize.width < valueInt;
case opGreater:
return (entry) => entry.displaySize.width > valueInt;
}
break;
case keyContentHeight:
if (valueInt == null) return null;
switch (op) {
case opEqual:
return (entry) => entry.displaySize.height == valueInt;
case opLower:
return (entry) => entry.displaySize.height < valueInt;
case opGreater:
return (entry) => entry.displaySize.height > valueInt;
}
break;
case keyContentSize:
match = _fileSizePattern.firstMatch(valueString);
if (match == null) return null;
valueString = match.group(1)?.trim();
if (valueString == null) return null;
final valueInt = int.tryParse(valueString);
if (valueInt == null) return null;
var bytes = valueInt;
final multiplierString = match.group(2)?.trim();
switch (multiplierString) {
case 'K':
bytes *= kilo;
break;
case 'M':
bytes *= mega;
break;
case 'G':
bytes *= giga;
break;
}
switch (op) {
case opEqual:
return (entry) => (entry.sizeBytes ?? 0) == bytes;
case opLower:
return (entry) => (entry.sizeBytes ?? 0) < bytes;
case opGreater:
return (entry) => (entry.sizeBytes ?? 0) > bytes;
}
break;
}
return null;
}
}

View file

@ -1,16 +1,16 @@
import 'package:intl/intl.dart';
const _kiloDivider = 1024;
const _megaDivider = _kiloDivider * _kiloDivider;
const _gigaDivider = _megaDivider * _kiloDivider;
const _teraDivider = _gigaDivider * _kiloDivider;
const kilo = 1024;
const mega = kilo * kilo;
const giga = mega * kilo;
const tera = giga * kilo;
String formatFileSize(String locale, int size, {int round = 2}) {
if (size < _kiloDivider) return '$size B';
if (size < kilo) return '$size B';
final formatter = NumberFormat('0${round > 0 ? '.${'0' * round}' : ''}', locale);
if (size < _megaDivider) return '${formatter.format(size / _kiloDivider)} KB';
if (size < _gigaDivider) return '${formatter.format(size / _megaDivider)} MB';
if (size < _teraDivider) return '${formatter.format(size / _gigaDivider)} GB';
return '${formatter.format(size / _teraDivider)} TB';
if (size < mega) return '${formatter.format(size / kilo)} KB';
if (size < giga) return '${formatter.format(size / mega)} MB';
if (size < tera) return '${formatter.format(size / giga)} GB';
return '${formatter.format(size / tera)} TB';
}