Select before and select after.

This commit is contained in:
stonegate 2020-10-12 01:24:19 +08:00
parent 7f66ebd7e6
commit 2e0e65f41a
2 changed files with 258 additions and 83 deletions

View File

@ -671,40 +671,78 @@ class DBHelper {
var list = <Map>[]; var list = <Map>[];
if (hideListened) { if (hideListened) {
if (count == -1) { if (count == -1) {
switch (filter) { if (reverse) {
case Filter.all: switch (filter) {
list = await dbClient.rawQuery( case Filter.all:
"""SELECT E.title, E.enclosure_url, E.enclosure_length, list = await dbClient.rawQuery(
"""SELECT E.title, E.enclosure_url, E.enclosure_length,
E.milliseconds, P.imagePath, P.title as feed_title, E.duration, E.explicit, E.milliseconds, P.imagePath, P.title as feed_title, E.duration, E.explicit,
P.primaryColor FROM Episodes E INNER JOIN PodcastLocal P ON E.feed_id = P.id P.primaryColor FROM Episodes E INNER JOIN PodcastLocal P ON E.feed_id = P.id
LEFT JOIN PlayHistory H ON E.enclosure_url = H.enclosure_url LEFT JOIN PlayHistory H ON E.enclosure_url = H.enclosure_url
WHERE P.id = ? GROUP BY E.enclosure_url HAVING SUM(H.listen_time) is null WHERE P.id = ? GROUP BY E.enclosure_url HAVING SUM(H.listen_time) is null
OR SUM(H.listen_time) = 0 ORDER BY E.milliseconds ASC""", [id]); OR SUM(H.listen_time) = 0 ORDER BY E.milliseconds ASC""", [id]);
break; break;
case Filter.liked: case Filter.liked:
list = await dbClient.rawQuery( list = await dbClient.rawQuery(
"""SELECT E.title, E.enclosure_url, E.enclosure_length, """SELECT E.title, E.enclosure_url, E.enclosure_length,
E.milliseconds, P.imagePath, P.title as feed_title, E.duration, E.explicit, E.milliseconds, P.imagePath, P.title as feed_title, E.duration, E.explicit,
P.primaryColor FROM Episodes E INNER JOIN PodcastLocal P ON E.feed_id = P.id P.primaryColor FROM Episodes E INNER JOIN PodcastLocal P ON E.feed_id = P.id
WHERE P.id = ? AND E.liked = 1 ORDER BY E.milliseconds ASC""", [id]); WHERE P.id = ? AND E.liked = 1 ORDER BY E.milliseconds ASC""", [id]);
break; break;
case Filter.downloaded: case Filter.downloaded:
list = await dbClient.rawQuery( list = await dbClient.rawQuery(
"""SELECT E.title, E.enclosure_url, E.enclosure_length, """SELECT E.title, E.enclosure_url, E.enclosure_length,
E.milliseconds, P.imagePath, P.title as feed_title, E.duration, E.explicit, E.milliseconds, P.imagePath, P.title as feed_title, E.duration, E.explicit,
P.primaryColor FROM Episodes E INNER JOIN PodcastLocal P ON E.feed_id = P.id P.primaryColor FROM Episodes E INNER JOIN PodcastLocal P ON E.feed_id = P.id
WHERE P.id = ? AND E.media_id != E.enclosure_url ORDER BY E.milliseconds ASC""", WHERE P.id = ? AND E.media_id != E.enclosure_url ORDER BY E.milliseconds ASC""",
[id]); [id]);
break; break;
case Filter.search: case Filter.search:
list = await dbClient.rawQuery( list = await dbClient.rawQuery(
"""SELECT E.title, E.enclosure_url, E.enclosure_length, """SELECT E.title, E.enclosure_url, E.enclosure_length,
E.milliseconds, P.imagePath, P.title as feed_title, E.duration, E.explicit, E.milliseconds, P.imagePath, P.title as feed_title, E.duration, E.explicit,
P.primaryColor FROM Episodes E INNER JOIN PodcastLocal P ON E.feed_id = P.id P.primaryColor FROM Episodes E INNER JOIN PodcastLocal P ON E.feed_id = P.id
WHERE P.id = ? AND E.title LIKE ? ORDER BY E.milliseconds ASC""", WHERE P.id = ? AND E.title LIKE ? ORDER BY E.milliseconds ASC""",
[id, '%$query%']); [id, '%$query%']);
break; break;
default: default:
}
} else {
switch (filter) {
case Filter.all:
list = await dbClient.rawQuery(
"""SELECT E.title, E.enclosure_url, E.enclosure_length,
E.milliseconds, P.imagePath, P.title as feed_title, E.duration, E.explicit,
P.primaryColor FROM Episodes E INNER JOIN PodcastLocal P ON E.feed_id = P.id
LEFT JOIN PlayHistory H ON E.enclosure_url = H.enclosure_url
WHERE P.id = ? GROUP BY E.enclosure_url HAVING SUM(H.listen_time) is null
OR SUM(H.listen_time) = 0 ORDER BY E.milliseconds DESC""", [id]);
break;
case Filter.liked:
list = await dbClient.rawQuery(
"""SELECT E.title, E.enclosure_url, E.enclosure_length,
E.milliseconds, P.imagePath, P.title as feed_title, E.duration, E.explicit,
P.primaryColor FROM Episodes E INNER JOIN PodcastLocal P ON E.feed_id = P.id
WHERE P.id = ? AND E.liked = 1 ORDER BY E.milliseconds DESC""", [id]);
break;
case Filter.downloaded:
list = await dbClient.rawQuery(
"""SELECT E.title, E.enclosure_url, E.enclosure_length,
E.milliseconds, P.imagePath, P.title as feed_title, E.duration, E.explicit,
P.primaryColor FROM Episodes E INNER JOIN PodcastLocal P ON E.feed_id = P.id
WHERE P.id = ? AND E.media_id != E.enclosure_url ORDER BY E.milliseconds DESC""",
[id]);
break;
case Filter.search:
list = await dbClient.rawQuery(
"""SELECT E.title, E.enclosure_url, E.enclosure_length,
E.milliseconds, P.imagePath, P.title as feed_title, E.duration, E.explicit,
P.primaryColor FROM Episodes E INNER JOIN PodcastLocal P ON E.feed_id = P.id
WHERE P.id = ? AND E.title LIKE ? ORDER BY E.milliseconds DESC""",
[id, '%$query%']);
break;
default:
}
} }
} else if (reverse) { } else if (reverse) {
switch (filter) { switch (filter) {
@ -798,38 +836,74 @@ class DBHelper {
} }
} else { } else {
if (count == -1) { if (count == -1) {
switch (filter) { if (reverse) {
case Filter.all: switch (filter) {
list = await dbClient.rawQuery( case Filter.all:
"""SELECT E.title, E.enclosure_url, E.enclosure_length, list = await dbClient.rawQuery(
"""SELECT E.title, E.enclosure_url, E.enclosure_length,
E.milliseconds, P.imagePath, P.title as feed_title, E.duration, E.explicit, E.milliseconds, P.imagePath, P.title as feed_title, E.duration, E.explicit,
P.primaryColor FROM Episodes E INNER JOIN PodcastLocal P ON E.feed_id = P.id P.primaryColor FROM Episodes E INNER JOIN PodcastLocal P ON E.feed_id = P.id
WHERE P.id = ? ORDER BY E.milliseconds ASC""", [id]); WHERE P.id = ? ORDER BY E.milliseconds ASC""", [id]);
break; break;
case Filter.liked: case Filter.liked:
list = await dbClient.rawQuery( list = await dbClient.rawQuery(
"""SELECT E.title, E.enclosure_url, E.enclosure_length, """SELECT E.title, E.enclosure_url, E.enclosure_length,
E.milliseconds, P.imagePath, P.title as feed_title, E.duration, E.explicit, E.milliseconds, P.imagePath, P.title as feed_title, E.duration, E.explicit,
P.primaryColor FROM Episodes E INNER JOIN PodcastLocal P ON E.feed_id = P.id P.primaryColor FROM Episodes E INNER JOIN PodcastLocal P ON E.feed_id = P.id
WHERE P.id = ? AND E.liked = 1 ORDER BY E.milliseconds ASC""", [id]); WHERE P.id = ? AND E.liked = 1 ORDER BY E.milliseconds ASC""", [id]);
break; break;
case Filter.downloaded: case Filter.downloaded:
list = await dbClient.rawQuery( list = await dbClient.rawQuery(
"""SELECT E.title, E.enclosure_url, E.enclosure_length, """SELECT E.title, E.enclosure_url, E.enclosure_length,
E.milliseconds, P.imagePath, P.title as feed_title, E.duration, E.explicit, E.milliseconds, P.imagePath, P.title as feed_title, E.duration, E.explicit,
P.primaryColor FROM Episodes E INNER JOIN PodcastLocal P ON E.feed_id = P.id P.primaryColor FROM Episodes E INNER JOIN PodcastLocal P ON E.feed_id = P.id
WHERE P.id = ? AND E.media_id != E.enclosure_url ORDER BY E.milliseconds ASC""", WHERE P.id = ? AND E.media_id != E.enclosure_url ORDER BY E.milliseconds ASC""",
[id]); [id]);
break; break;
case Filter.search: case Filter.search:
list = await dbClient.rawQuery( list = await dbClient.rawQuery(
"""SELECT E.title, E.enclosure_url, E.enclosure_length, """SELECT E.title, E.enclosure_url, E.enclosure_length,
E.milliseconds, P.imagePath, P.title as feed_title, E.duration, E.explicit, E.milliseconds, P.imagePath, P.title as feed_title, E.duration, E.explicit,
P.primaryColor FROM Episodes E INNER JOIN PodcastLocal P ON E.feed_id = P.id P.primaryColor FROM Episodes E INNER JOIN PodcastLocal P ON E.feed_id = P.id
WHERE P.id = ? AND E.title LIKE ? ORDER BY E.milliseconds ASC""", WHERE P.id = ? AND E.title LIKE ? ORDER BY E.milliseconds ASC""",
[id, '%$query%']); [id, '%$query%']);
break; break;
default: default:
}
} else {
switch (filter) {
case Filter.all:
list = await dbClient.rawQuery(
"""SELECT E.title, E.enclosure_url, E.enclosure_length,
E.milliseconds, P.imagePath, P.title as feed_title, E.duration, E.explicit,
P.primaryColor FROM Episodes E INNER JOIN PodcastLocal P ON E.feed_id = P.id
WHERE P.id = ? ORDER BY E.milliseconds DESC""", [id]);
break;
case Filter.liked:
list = await dbClient.rawQuery(
"""SELECT E.title, E.enclosure_url, E.enclosure_length,
E.milliseconds, P.imagePath, P.title as feed_title, E.duration, E.explicit,
P.primaryColor FROM Episodes E INNER JOIN PodcastLocal P ON E.feed_id = P.id
WHERE P.id = ? AND E.liked = 1 ORDER BY E.milliseconds DESC""", [id]);
break;
case Filter.downloaded:
list = await dbClient.rawQuery(
"""SELECT E.title, E.enclosure_url, E.enclosure_length,
E.milliseconds, P.imagePath, P.title as feed_title, E.duration, E.explicit,
P.primaryColor FROM Episodes E INNER JOIN PodcastLocal P ON E.feed_id = P.id
WHERE P.id = ? AND E.media_id != E.enclosure_url ORDER BY E.milliseconds DESC""",
[id]);
break;
case Filter.search:
list = await dbClient.rawQuery(
"""SELECT E.title, E.enclosure_url, E.enclosure_length,
E.milliseconds, P.imagePath, P.title as feed_title, E.duration, E.explicit,
P.primaryColor FROM Episodes E INNER JOIN PodcastLocal P ON E.feed_id = P.id
WHERE P.id = ? AND E.title LIKE ? ORDER BY E.milliseconds DESC""",
[id, '%$query%']);
break;
default:
}
} }
} else if (reverse) { } else if (reverse) {
switch (filter) { switch (filter) {

View File

@ -86,6 +86,10 @@ class _PodcastDetailState extends State<PodcastDetail> {
bool _selectAll; bool _selectAll;
bool _selectBefore;
bool _selectAfter;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
@ -95,6 +99,8 @@ class _PodcastDetailState extends State<PodcastDetail> {
_scroll = false; _scroll = false;
_multiSelect = false; _multiSelect = false;
_selectAll = false; _selectAll = false;
_selectAfter = false;
_selectBefore = false;
} }
@override @override
@ -696,6 +702,7 @@ class _PodcastDetailState extends State<PodcastDetail> {
), ),
onPressed: () { onPressed: () {
setState(() { setState(() {
_top = -1;
_selectedEpisodes = []; _selectedEpisodes = [];
_multiSelect = true; _multiSelect = true;
}); });
@ -862,32 +869,48 @@ class _PodcastDetailState extends State<PodcastDetail> {
filter: _filter, filter: _filter,
query: _query), query: _query),
builder: (context, snapshot) { builder: (context, snapshot) {
if (_selectAll) { if (snapshot.hasData) {
_selectedEpisodes = snapshot.data; if (_selectAll) {
_selectedEpisodes = snapshot.data;
}
if (_selectBefore) {
final index = snapshot.data
.indexOf(_selectedEpisodes.first);
if (index != 0) {
_selectedEpisodes = snapshot.data
.sublist(0, index + 1);
}
}
if (_selectAfter) {
final index = snapshot.data
.indexOf(_selectedEpisodes.first);
_selectedEpisodes =
snapshot.data.sublist(index);
}
return EpisodeGrid(
episodes: snapshot.data,
showFavorite: true,
showNumber: _filter == Filter.all &&
!_hideListened
? true
: false,
layout: _layout,
reverse: _reverse,
episodeCount: _episodeCount,
initNum: _scroll ? 0 : 12,
multiSelect: _multiSelect,
selectedList: _selectedEpisodes ?? [],
onSelect: (value) => setState(() {
_selectAll = false;
_selectBefore = false;
_selectAfter = false;
_selectedEpisodes = value;
}),
);
} }
return (snapshot.hasData) return SliverToBoxAdapter(
? EpisodeGrid( child: Center(),
episodes: snapshot.data, );
showFavorite: true,
showNumber: _filter == Filter.all &&
!_hideListened
? true
: false,
layout: _layout,
reverse: _reverse,
episodeCount: _episodeCount,
initNum: _scroll ? 0 : 12,
multiSelect: _multiSelect,
selectedList:
_selectedEpisodes ?? [],
onSelect: (value) => setState(() {
_selectAll = false;
_selectedEpisodes = value;
}),
)
: SliverToBoxAdapter(
child: Center(),
);
}), }),
SliverList( SliverList(
delegate: SliverChildBuilderDelegate( delegate: SliverChildBuilderDelegate(
@ -919,7 +942,23 @@ class _PodcastDetailState extends State<PodcastDetail> {
onSelectAll: (value) { onSelectAll: (value) {
setState(() { setState(() {
_selectAll = value; _selectAll = value;
_selectedEpisodes = []; _selectAfter = false;
_selectBefore = false;
if (!value) {
_selectedEpisodes = [];
}
});
},
onSelectAfter: (value) {
setState(() {
_selectBefore = false;
_selectAfter = true;
});
},
onSelectBefore: (value) {
setState(() {
_selectAfter = false;
_selectBefore = true;
}); });
}, },
onClose: (value) { onClose: (value) {
@ -927,6 +966,8 @@ class _PodcastDetailState extends State<PodcastDetail> {
if (value) { if (value) {
_multiSelect = false; _multiSelect = false;
_selectAll = false; _selectAll = false;
_selectAfter = false;
_selectBefore = false;
} }
}); });
}, },
@ -959,12 +1000,16 @@ class MultiSelectMenuBar extends StatefulWidget {
this.selectAll, this.selectAll,
this.onSelectAll, this.onSelectAll,
this.onClose, this.onClose,
this.onSelectAfter,
this.onSelectBefore,
Key key}) Key key})
: super(key: key); : super(key: key);
final List<EpisodeBrief> selectedList; final List<EpisodeBrief> selectedList;
final bool selectAll; final bool selectAll;
final ValueChanged<bool> onSelectAll; final ValueChanged<bool> onSelectAll;
final ValueChanged<bool> onClose; final ValueChanged<bool> onClose;
final ValueChanged<bool> onSelectBefore;
final ValueChanged<bool> onSelectAfter;
@override @override
_MultiSelectMenuBarState createState() => _MultiSelectMenuBarState(); _MultiSelectMenuBarState createState() => _MultiSelectMenuBarState();
@ -1146,22 +1191,84 @@ class _MultiSelectMenuBarState extends State<MultiSelectMenuBar> {
tween: Tween<double>(begin: 0, end: 1), tween: Tween<double>(begin: 0, end: 1),
duration: Duration(milliseconds: 500), duration: Duration(milliseconds: 500),
builder: (context, value, child) => Container( builder: (context, value, child) => Container(
height: 80.0 * value, height: 90.0 * value,
decoration: BoxDecoration(color: context.primaryColor), decoration: BoxDecoration(color: context.primaryColor),
child: SingleChildScrollView( child: SingleChildScrollView(
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
SizedBox( Row(
height: 30, crossAxisAlignment: CrossAxisAlignment.center,
child: Align( children: [
alignment: Alignment.centerRight, SizedBox(
child: Padding( height: 40,
padding: EdgeInsets.symmetric(horizontal: 20.0), child: Center(
child: Text('${widget.selectedList.length} selected', child: Padding(
style: context.textTheme.headline6 padding: EdgeInsets.symmetric(horizontal: 20.0),
.copyWith(color: context.accentColor))), child: Text('${widget.selectedList.length} selected',
), style: context.textTheme.headline6
.copyWith(color: context.accentColor))),
),
),
Spacer(),
if (widget.selectedList.length == 1)
SizedBox(
height: 25,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 5),
child: OutlinedButton(
style: OutlinedButton.styleFrom(
side: BorderSide(color: context.accentColor),
primary: context.textColor,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(
Radius.circular(100)))),
onPressed: () {
widget.onSelectBefore(true);
},
child: Text('Before')),
),
),
if (widget.selectedList.length == 1)
SizedBox(
height: 25,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 5),
child: OutlinedButton(
style: OutlinedButton.styleFrom(
side: BorderSide(color: context.accentColor),
primary: context.textColor,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(
Radius.circular(100)))),
onPressed: () {
widget.onSelectAfter(true);
},
child: Text('After')),
),
),
SizedBox(
height: 25,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 5),
child: OutlinedButton(
style: OutlinedButton.styleFrom(
side: BorderSide(color: context.accentColor),
backgroundColor:
widget.selectAll ? context.accentColor : null,
primary: widget.selectAll
? Colors.white
: context.textColor,
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.all(Radius.circular(100)))),
onPressed: () {
widget.onSelectAll(!widget.selectAll);
},
child: Text('All')),
),
)
],
), ),
Row( Row(
children: [ children: [
@ -1287,12 +1394,6 @@ class _MultiSelectMenuBarState extends State<MultiSelectMenuBar> {
} }
}), }),
Spacer(), Spacer(),
_buttonOnMenu(
child: Icon(Icons.select_all_rounded,
color: widget.selectAll ? context.accentColor : null),
onTap: () {
widget.onSelectAll(!widget.selectAll);
}),
_buttonOnMenu( _buttonOnMenu(
child: Icon(Icons.close), child: Icon(Icons.close),
onTap: () => widget.onClose(true)) onTap: () => widget.onClose(true))