bookmark and history deletable

This commit is contained in:
DASHU
2024-09-27 11:48:29 +08:00
parent 1b04d52f14
commit c121370c3b
7 changed files with 241 additions and 101 deletions

View File

@@ -0,0 +1,65 @@
import 'package:bot_toast/bot_toast.dart';
import 'package:flutter/material.dart';
import '../const/base.dart';
mixin DeletableListMixin<T extends StatefulWidget> on State<T> {
bool deleting = false;
List<Widget> genAppBarActions(BuildContext context) {
return deleting
? [
GestureDetector(
onTap: delete,
child: Container(
padding: const EdgeInsets.all(Base.BASE_PADDING),
child: Icon(Icons.delete_sweep_outlined),
),
),
]
: [];
}
Widget wrapListItem(Widget child,
{required Function onTap, required Function onSelect}) {
if (deleting) {
return GestureDetector(
onTap: () {
onSelect();
},
child: child,
);
} else {
return GestureDetector(
onTap: () {
onTap();
},
onLongPress: () {
setState(() {
deleting = true;
});
onSelect();
},
child: child,
);
}
}
Future<void> delete() async {
var cancelFunc = BotToast.showLoading();
try {
await doDelete();
} catch (e) {
print("delete error " + e.toString());
} finally {
cancelFunc.call();
}
setState(() {
deleting = false;
});
}
Future<void> doDelete() async {}
}

View File

@@ -3,6 +3,10 @@ import 'package:nowser/component/image_component.dart';
import 'package:nowser/const/base.dart';
class UrlListItemComponnet extends StatefulWidget {
bool selected;
bool selectable;
String? image;
String title;
@@ -12,6 +16,8 @@ class UrlListItemComponnet extends StatefulWidget {
int? dateTime;
UrlListItemComponnet({
this.selected = false,
this.selectable = false,
this.image,
required this.title,
required this.url,
@@ -30,6 +36,16 @@ class _UrlListItemComponnet extends State<UrlListItemComponnet> {
var themeData = Theme.of(context);
var smallFontSize = themeData.textTheme.bodySmall!.fontSize;
List<Widget> list = [];
if (widget.selectable) {
list.add(Container(
child: Checkbox(
value: widget.selected,
onChanged: (bool? value) {},
),
));
}
Widget iconWidget = Icon(
Icons.image,
weight: 60,
@@ -43,6 +59,13 @@ class _UrlListItemComponnet extends State<UrlListItemComponnet> {
);
}
list.add(Container(
width: 60,
height: 60,
alignment: Alignment.center,
child: iconWidget,
));
String host = widget.url;
try {
var uri = Uri.parse(widget.url);
@@ -55,68 +78,62 @@ class _UrlListItemComponnet extends State<UrlListItemComponnet> {
time = "${dt.hour}:${dt.minute}";
}
list.add(Expanded(
child: Container(
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(
width: 1, color: themeData.hintColor.withOpacity(0.5)),
),
),
child: Row(
children: [
Expanded(
child: Container(
margin: EdgeInsets.only(
top: Base.BASE_PADDING_HALF,
bottom: Base.BASE_PADDING_HALF,
),
padding: EdgeInsets.only(right: Base.BASE_PADDING_HALF),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
widget.title,
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
Text(
host,
style: TextStyle(
fontSize: smallFontSize,
color: themeData.hintColor,
),
),
],
),
),
),
Container(
child: Text(
time,
style: TextStyle(
color: themeData.hintColor,
),
),
),
],
),
),
));
return Container(
padding: EdgeInsets.only(
left: Base.BASE_PADDING,
right: Base.BASE_PADDING,
),
child: Row(
children: [
Container(
width: 60,
height: 60,
alignment: Alignment.center,
child: iconWidget,
),
Expanded(
child: Container(
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(
width: 1, color: themeData.hintColor.withOpacity(0.5)),
),
),
child: Row(
children: [
Expanded(
child: Container(
margin: EdgeInsets.only(
top: Base.BASE_PADDING_HALF,
bottom: Base.BASE_PADDING_HALF,
),
padding: EdgeInsets.only(right: Base.BASE_PADDING_HALF),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
widget.title,
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
Text(
host,
style: TextStyle(
fontSize: smallFontSize,
color: themeData.hintColor,
),
),
],
),
),
),
Container(
child: Text(
time,
style: TextStyle(
color: themeData.hintColor,
),
),
),
],
),
),
),
],
children: list,
),
);
}

View File

@@ -37,4 +37,16 @@ class AuthLogDB {
db = await DB.getDB(db);
db.execute("delete from auth_log where app_id = ?", [appId]);
}
static Future<void> deleteByIds(List<int> ids, {DatabaseExecutor? db}) async {
var sql = "delete from auth_log where id in(";
for (var id in ids) {
sql += "?,";
}
sql = sql.substring(0, sql.length - 1);
sql += ")";
db = await DB.getDB(db);
db.execute(sql, ids);
}
}

View File

@@ -27,4 +27,16 @@ class BookmarkDB {
}
return objs;
}
static Future<void> deleteByIds(List<int> ids, {DatabaseExecutor? db}) async {
var sql = "delete from bookmark where id in(";
for (var id in ids) {
sql += "?,";
}
sql = sql.substring(0, sql.length - 1);
sql += ")";
db = await DB.getDB(db);
await db.execute(sql, ids);
}
}

View File

@@ -27,4 +27,16 @@ class BrowserHistoryDB {
}
return objs;
}
static Future<void> deleteByIds(List<int> ids, {DatabaseExecutor? db}) async {
var sql = "delete from browser_history where id in(";
for (var id in ids) {
sql += "?,";
}
sql = sql.substring(0, sql.length - 1);
sql += ")";
db = await DB.getDB(db);
await db.execute(sql, ids);
}
}

View File

@@ -1,11 +1,10 @@
import 'package:flutter/material.dart';
import 'package:nowser/component/cust_state.dart';
import 'package:nowser/component/deletable_list_mixin.dart';
import 'package:nowser/component/url_list_item_componnet.dart';
import 'package:nowser/data/browser_history_db.dart';
import 'package:nowser/util/router_util.dart';
import '../../component/appbar_back_btn_component.dart';
import '../../const/base.dart';
import '../../data/bookmark.dart';
import '../../data/bookmark_db.dart';
@@ -16,7 +15,8 @@ class BookmarkRouter extends StatefulWidget {
}
}
class _BookmarkRouter extends CustState<BookmarkRouter> {
class _BookmarkRouter extends CustState<BookmarkRouter>
with DeletableListMixin {
List<Bookmark> bookmarks = [];
@override
@@ -25,6 +25,8 @@ class _BookmarkRouter extends CustState<BookmarkRouter> {
setState(() {});
}
List<int> selectedIds = [];
@override
Widget doBuild(BuildContext context) {
var themeData = Theme.of(context);
@@ -39,15 +41,7 @@ class _BookmarkRouter extends CustState<BookmarkRouter> {
fontSize: themeData.textTheme.bodyLarge!.fontSize,
),
),
actions: [
// GestureDetector(
// onTap: () {},
// child: Container(
// padding: const EdgeInsets.all(Base.BASE_PADDING),
// child: Icon(Icons.delete_sweep_outlined),
// ),
// ),
],
actions: genAppBarActions(context),
),
body: ListView.builder(
itemBuilder: (context, index) {
@@ -57,23 +51,39 @@ class _BookmarkRouter extends CustState<BookmarkRouter> {
var bookmark = bookmarks[index];
var main = Container(
child: GestureDetector(
onTap: () {
RouterUtil.back(context, bookmark.url);
},
child: UrlListItemComponnet(
image: bookmark.favicon,
title: bookmark.title ?? "",
url: bookmark.url ?? "",
),
),
Widget main = UrlListItemComponnet(
selectable: deleting,
selected: selectedIds.contains(bookmark.id),
image: bookmark.favicon,
title: bookmark.title ?? "",
url: bookmark.url ?? "",
);
main = wrapListItem(main, onTap: () {
RouterUtil.back(context, bookmark.url);
}, onSelect: () {
if (!selectedIds.contains(bookmark.id)) {
setState(() {
selectedIds.add(bookmark.id!);
});
}
});
return main;
},
itemCount: bookmarks.length,
),
);
}
@override
Future<void> doDelete() async {
if (selectedIds.isNotEmpty) {
await BookmarkDB.deleteByIds(selectedIds);
bookmarks.removeWhere((o) {
return selectedIds.contains(o.id);
});
selectedIds.clear();
}
}
}

View File

@@ -1,5 +1,7 @@
import 'package:bot_toast/bot_toast.dart';
import 'package:flutter/material.dart';
import 'package:nowser/component/cust_state.dart';
import 'package:nowser/component/deletable_list_mixin.dart';
import 'package:nowser/component/url_list_item_componnet.dart';
import 'package:nowser/data/browser_history_db.dart';
import 'package:nowser/util/router_util.dart';
@@ -15,7 +17,7 @@ class HistoryRouter extends StatefulWidget {
}
}
class _HistoryRouter extends CustState<HistoryRouter> {
class _HistoryRouter extends CustState<HistoryRouter> with DeletableListMixin {
List<BrowserHistory> historys = [];
@override
@@ -24,6 +26,8 @@ class _HistoryRouter extends CustState<HistoryRouter> {
setState(() {});
}
List<int> selectedIds = [];
@override
Widget doBuild(BuildContext context) {
var themeData = Theme.of(context);
@@ -38,15 +42,7 @@ class _HistoryRouter extends CustState<HistoryRouter> {
fontSize: themeData.textTheme.bodyLarge!.fontSize,
),
),
actions: [
// GestureDetector(
// onTap: () {},
// child: Container(
// padding: const EdgeInsets.all(Base.BASE_PADDING),
// child: Icon(Icons.delete_sweep_outlined),
// ),
// ),
],
actions: genAppBarActions(context),
),
body: ListView.builder(
itemBuilder: (context, index) {
@@ -73,20 +69,25 @@ class _HistoryRouter extends CustState<HistoryRouter> {
}
}
var main = Container(
child: GestureDetector(
onTap: () {
RouterUtil.back(context, history.url);
},
child: UrlListItemComponnet(
image: history.favicon,
title: history.title ?? "",
url: history.url ?? "",
dateTime: history.createdAt,
),
),
Widget main = UrlListItemComponnet(
selectable: deleting,
selected: selectedIds.contains(history.id),
image: history.favicon,
title: history.title ?? "",
url: history.url ?? "",
dateTime: history.createdAt,
);
main = wrapListItem(main, onTap: () {
RouterUtil.back(context, history.url);
}, onSelect: () {
if (!selectedIds.contains(history.id)) {
setState(() {
selectedIds.add(history.id!);
});
}
});
if (dateWidget != null) {
return Column(
mainAxisSize: MainAxisSize.min,
@@ -100,4 +101,15 @@ class _HistoryRouter extends CustState<HistoryRouter> {
),
);
}
@override
Future<void> doDelete() async {
if (selectedIds.isNotEmpty) {
await BrowserHistoryDB.deleteByIds(selectedIds);
historys.removeWhere((o) {
return selectedIds.contains(o.id);
});
selectedIds.clear();
}
}
}