mirror of
https://github.com/venera-app/venera.git
synced 2025-09-27 15:57:25 +00:00
improve favorites page
This commit is contained in:
@@ -21,7 +21,7 @@ class ComicTile extends StatelessWidget {
|
|||||||
final VoidCallback? onTap;
|
final VoidCallback? onTap;
|
||||||
|
|
||||||
void _onTap() {
|
void _onTap() {
|
||||||
if(onTap != null) {
|
if (onTap != null) {
|
||||||
onTap!();
|
onTap!();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -192,6 +192,9 @@ class ComicTile extends StatelessWidget {
|
|||||||
badge: badge,
|
badge: badge,
|
||||||
tags: comic.tags,
|
tags: comic.tags,
|
||||||
maxLines: 2,
|
maxLines: 2,
|
||||||
|
enableTranslate: ComicSource.find(comic.sourceKey)
|
||||||
|
?.enableTagsTranslate ??
|
||||||
|
false,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -274,13 +277,15 @@ class ComicTile extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _ComicDescription extends StatelessWidget {
|
class _ComicDescription extends StatelessWidget {
|
||||||
const _ComicDescription(
|
const _ComicDescription({
|
||||||
{required this.title,
|
required this.title,
|
||||||
required this.subtitle,
|
required this.subtitle,
|
||||||
required this.description,
|
required this.description,
|
||||||
|
required this.enableTranslate,
|
||||||
this.badge,
|
this.badge,
|
||||||
this.maxLines = 2,
|
this.maxLines = 2,
|
||||||
this.tags});
|
this.tags,
|
||||||
|
});
|
||||||
|
|
||||||
final String title;
|
final String title;
|
||||||
final String subtitle;
|
final String subtitle;
|
||||||
@@ -288,13 +293,15 @@ class _ComicDescription extends StatelessWidget {
|
|||||||
final String? badge;
|
final String? badge;
|
||||||
final List<String>? tags;
|
final List<String>? tags;
|
||||||
final int maxLines;
|
final int maxLines;
|
||||||
|
final bool enableTranslate;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
if (tags != null) {
|
if (tags != null) {
|
||||||
tags!.removeWhere((element) => element.removeAllBlank == "");
|
tags!.removeWhere((element) => element.removeAllBlank == "");
|
||||||
}
|
}
|
||||||
var enableTranslate = App.locale.languageCode == 'zh';
|
var enableTranslate =
|
||||||
|
App.locale.languageCode == 'zh' && this.enableTranslate;
|
||||||
return Column(
|
return Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
@@ -583,6 +590,7 @@ class ComicList extends StatefulWidget {
|
|||||||
this.leadingSliver,
|
this.leadingSliver,
|
||||||
this.trailingSliver,
|
this.trailingSliver,
|
||||||
this.errorLeading,
|
this.errorLeading,
|
||||||
|
this.menuBuilder,
|
||||||
});
|
});
|
||||||
|
|
||||||
final Future<Res<List<Comic>>> Function(int page)? loadPage;
|
final Future<Res<List<Comic>>> Function(int page)? loadPage;
|
||||||
@@ -595,32 +603,45 @@ class ComicList extends StatefulWidget {
|
|||||||
|
|
||||||
final Widget? errorLeading;
|
final Widget? errorLeading;
|
||||||
|
|
||||||
|
final List<MenuEntry> Function(Comic)? menuBuilder;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<ComicList> createState() => _ComicListState();
|
State<ComicList> createState() => ComicListState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _ComicListState extends State<ComicList> {
|
class ComicListState extends State<ComicList> {
|
||||||
int? maxPage;
|
int? _maxPage;
|
||||||
|
|
||||||
Map<int, List<Comic>> data = {};
|
final Map<int, List<Comic>> _data = {};
|
||||||
|
|
||||||
int page = 1;
|
int _page = 1;
|
||||||
|
|
||||||
String? error;
|
String? _error;
|
||||||
|
|
||||||
Map<int, bool> loading = {};
|
final Map<int, bool> _loading = {};
|
||||||
|
|
||||||
String? nextUrl;
|
String? _nextUrl;
|
||||||
|
|
||||||
Widget buildPageSelector() {
|
void remove(Comic c) {
|
||||||
|
if(_data[_page] == null || !_data[_page]!.remove(c)) {
|
||||||
|
for(var page in _data.values) {
|
||||||
|
if(page.remove(c)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setState(() {});
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildPageSelector() {
|
||||||
return Row(
|
return Row(
|
||||||
children: [
|
children: [
|
||||||
FilledButton(
|
FilledButton(
|
||||||
onPressed: page > 1
|
onPressed: _page > 1
|
||||||
? () {
|
? () {
|
||||||
setState(() {
|
setState(() {
|
||||||
error = null;
|
_error = null;
|
||||||
page--;
|
_page--;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
: null,
|
: null,
|
||||||
@@ -661,10 +682,10 @@ class _ComicListState extends State<ComicList> {
|
|||||||
context.showMessage(message: "Invalid page".tl);
|
context.showMessage(message: "Invalid page".tl);
|
||||||
} else {
|
} else {
|
||||||
if (page > 0 &&
|
if (page > 0 &&
|
||||||
(maxPage == null || page <= maxPage!)) {
|
(_maxPage == null || page <= _maxPage!)) {
|
||||||
setState(() {
|
setState(() {
|
||||||
error = null;
|
_error = null;
|
||||||
this.page = page;
|
this._page = page;
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
context.showMessage(
|
context.showMessage(
|
||||||
@@ -682,18 +703,18 @@ class _ComicListState extends State<ComicList> {
|
|||||||
child: Padding(
|
child: Padding(
|
||||||
padding:
|
padding:
|
||||||
const EdgeInsets.symmetric(horizontal: 16, vertical: 6),
|
const EdgeInsets.symmetric(horizontal: 16, vertical: 6),
|
||||||
child: Text("Page $page / ${maxPage ?? '?'}"),
|
child: Text("Page $_page / ${_maxPage ?? '?'}"),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
FilledButton(
|
FilledButton(
|
||||||
onPressed: page < (maxPage ?? (page + 1))
|
onPressed: _page < (_maxPage ?? (_page + 1))
|
||||||
? () {
|
? () {
|
||||||
setState(() {
|
setState(() {
|
||||||
error = null;
|
_error = null;
|
||||||
page++;
|
_page++;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
: null,
|
: null,
|
||||||
@@ -703,63 +724,63 @@ class _ComicListState extends State<ComicList> {
|
|||||||
).paddingVertical(8).paddingHorizontal(16);
|
).paddingVertical(8).paddingHorizontal(16);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget buildSliverPageSelector() {
|
Widget _buildSliverPageSelector() {
|
||||||
return SliverToBoxAdapter(
|
return SliverToBoxAdapter(
|
||||||
child: buildPageSelector(),
|
child: _buildPageSelector(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> loadPage(int page) async {
|
Future<void> _loadPage(int page) async {
|
||||||
if (loading[page] == true) {
|
if (_loading[page] == true) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
loading[page] = true;
|
_loading[page] = true;
|
||||||
try {
|
try {
|
||||||
if (widget.loadPage != null) {
|
if (widget.loadPage != null) {
|
||||||
var res = await widget.loadPage!(page);
|
var res = await widget.loadPage!(page);
|
||||||
if (res.success) {
|
if (res.success) {
|
||||||
if (res.data.isEmpty) {
|
if (res.data.isEmpty) {
|
||||||
data[page] = const [];
|
_data[page] = const [];
|
||||||
setState(() {
|
setState(() {
|
||||||
maxPage = page;
|
_maxPage = page;
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
setState(() {
|
setState(() {
|
||||||
data[page] = res.data;
|
_data[page] = res.data;
|
||||||
if (res.subData != null && res.subData is int) {
|
if (res.subData != null && res.subData is int) {
|
||||||
maxPage = res.subData;
|
_maxPage = res.subData;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
setState(() {
|
setState(() {
|
||||||
error = res.errorMessage ?? "Unknown error".tl;
|
_error = res.errorMessage ?? "Unknown error".tl;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
while (data[page] == null) {
|
while (_data[page] == null) {
|
||||||
await fetchNext();
|
await _fetchNext();
|
||||||
}
|
}
|
||||||
setState(() {});
|
setState(() {});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
setState(() {
|
setState(() {
|
||||||
error = e.toString();
|
_error = e.toString();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
loading[page] = false;
|
_loading[page] = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> fetchNext() async {
|
Future<void> _fetchNext() async {
|
||||||
var res = await widget.loadNext!(nextUrl);
|
var res = await widget.loadNext!(_nextUrl);
|
||||||
data[data.length + 1] = res.data;
|
_data[_data.length + 1] = res.data;
|
||||||
if (res.subData['next'] == null) {
|
if (res.subData['next'] == null) {
|
||||||
maxPage = data.length;
|
_maxPage = _data.length;
|
||||||
} else {
|
} else {
|
||||||
nextUrl = res.subData['next'];
|
_nextUrl = res.subData['next'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -768,18 +789,18 @@ class _ComicListState extends State<ComicList> {
|
|||||||
if (widget.loadPage == null && widget.loadNext == null) {
|
if (widget.loadPage == null && widget.loadNext == null) {
|
||||||
throw Exception("loadPage and loadNext can't be null at the same time");
|
throw Exception("loadPage and loadNext can't be null at the same time");
|
||||||
}
|
}
|
||||||
if (error != null) {
|
if (_error != null) {
|
||||||
return Column(
|
return Column(
|
||||||
children: [
|
children: [
|
||||||
if (widget.errorLeading != null) widget.errorLeading!,
|
if (widget.errorLeading != null) widget.errorLeading!,
|
||||||
buildPageSelector(),
|
_buildPageSelector(),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: NetworkError(
|
child: NetworkError(
|
||||||
withAppbar: false,
|
withAppbar: false,
|
||||||
message: error!,
|
message: _error!,
|
||||||
retry: () {
|
retry: () {
|
||||||
setState(() {
|
setState(() {
|
||||||
error = null;
|
_error = null;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@@ -787,8 +808,8 @@ class _ComicListState extends State<ComicList> {
|
|||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (data[page] == null) {
|
if (_data[_page] == null) {
|
||||||
loadPage(page);
|
_loadPage(_page);
|
||||||
return const Center(
|
return const Center(
|
||||||
child: CircularProgressIndicator(),
|
child: CircularProgressIndicator(),
|
||||||
);
|
);
|
||||||
@@ -796,9 +817,12 @@ class _ComicListState extends State<ComicList> {
|
|||||||
return SmoothCustomScrollView(
|
return SmoothCustomScrollView(
|
||||||
slivers: [
|
slivers: [
|
||||||
if (widget.leadingSliver != null) widget.leadingSliver!,
|
if (widget.leadingSliver != null) widget.leadingSliver!,
|
||||||
buildSliverPageSelector(),
|
_buildSliverPageSelector(),
|
||||||
SliverGridComics(comics: data[page] ?? const []),
|
SliverGridComics(
|
||||||
if (data[page]!.length > 6) buildSliverPageSelector(),
|
comics: _data[_page] ?? const [],
|
||||||
|
menuBuilder: widget.menuBuilder,
|
||||||
|
),
|
||||||
|
if (_data[_page]!.length > 6) _buildSliverPageSelector(),
|
||||||
if (widget.trailingSliver != null) widget.trailingSliver!,
|
if (widget.trailingSliver != null) widget.trailingSliver!,
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
@@ -12,12 +12,16 @@ class Comment {
|
|||||||
final int? voteStatus; // 1: upvote, -1: downvote, 0: none
|
final int? voteStatus; // 1: upvote, -1: downvote, 0: none
|
||||||
|
|
||||||
static String? parseTime(dynamic value) {
|
static String? parseTime(dynamic value) {
|
||||||
if(value == null) return null;
|
if (value == null) return null;
|
||||||
if(value is int) {
|
if (value is int) {
|
||||||
if(value < 10000000000) {
|
if (value < 10000000000) {
|
||||||
return DateTime.fromMillisecondsSinceEpoch(value * 1000).toString().substring(0, 19);
|
return DateTime.fromMillisecondsSinceEpoch(value * 1000)
|
||||||
|
.toString()
|
||||||
|
.substring(0, 19);
|
||||||
} else {
|
} else {
|
||||||
return DateTime.fromMillisecondsSinceEpoch(value).toString().substring(0, 19);
|
return DateTime.fromMillisecondsSinceEpoch(value)
|
||||||
|
.toString()
|
||||||
|
.substring(0, 19);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return value.toString();
|
return value.toString();
|
||||||
@@ -89,6 +93,15 @@ class Comic {
|
|||||||
description = json["description"] ?? "",
|
description = json["description"] ?? "",
|
||||||
maxPage = json["maxPage"],
|
maxPage = json["maxPage"],
|
||||||
language = json["language"];
|
language = json["language"];
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
if (other is! Comic) return false;
|
||||||
|
return other.id == id && other.sourceKey == sourceKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode => id.hashCode ^ sourceKey.hashCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
class ComicDetails with HistoryMixin {
|
class ComicDetails with HistoryMixin {
|
||||||
|
@@ -1,3 +1,5 @@
|
|||||||
|
import 'dart:math';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_reorderable_grid_view/widgets/reorderable_builder.dart';
|
import 'package:flutter_reorderable_grid_view/widgets/reorderable_builder.dart';
|
||||||
import 'package:venera/components/components.dart';
|
import 'package:venera/components/components.dart';
|
||||||
@@ -90,9 +92,8 @@ class _FavoritesPageState extends State<FavoritesPage> {
|
|||||||
return Align(
|
return Align(
|
||||||
alignment: Alignment.centerLeft,
|
alignment: Alignment.centerLeft,
|
||||||
child: Material(
|
child: Material(
|
||||||
color: context.colorScheme.surfaceContainerLow,
|
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
width: 256,
|
width: min(300, context.width-16),
|
||||||
child: _LeftBar(
|
child: _LeftBar(
|
||||||
withAppbar: true,
|
withAppbar: true,
|
||||||
favPage: this,
|
favPage: this,
|
||||||
|
@@ -1,5 +1,59 @@
|
|||||||
part of 'favorites_page.dart';
|
part of 'favorites_page.dart';
|
||||||
|
|
||||||
|
// TODO: Add a menu option to delete a comic from favorites
|
||||||
|
|
||||||
|
Future<bool> _deleteComic(String cid, String? fid, String sourceKey) async {
|
||||||
|
var source = ComicSource.find(sourceKey);
|
||||||
|
if (source == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = false;
|
||||||
|
|
||||||
|
await showDialog(
|
||||||
|
context: App.rootContext,
|
||||||
|
builder: (context) {
|
||||||
|
bool loading = false;
|
||||||
|
return StatefulBuilder(builder: (context, setState) {
|
||||||
|
return ContentDialog(
|
||||||
|
title: "Delete".tl,
|
||||||
|
content: Text("Are you sure you want to delete this comic?".tl)
|
||||||
|
.paddingHorizontal(16),
|
||||||
|
actions: [
|
||||||
|
Button.filled(
|
||||||
|
isLoading: loading,
|
||||||
|
color: context.colorScheme.error,
|
||||||
|
onPressed: () async {
|
||||||
|
setState(() {
|
||||||
|
loading = true;
|
||||||
|
});
|
||||||
|
var res = await source.favoriteData!.addOrDelFavorite!(
|
||||||
|
cid,
|
||||||
|
fid ?? '',
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
if (res.success) {
|
||||||
|
context.showMessage(message: "Deleted".tl);
|
||||||
|
result = true;
|
||||||
|
context.pop();
|
||||||
|
} else {
|
||||||
|
setState(() {
|
||||||
|
loading = false;
|
||||||
|
});
|
||||||
|
context.showMessage(message: res.errorMessage!);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: Text("Confirm".tl),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
class NetworkFavoritePage extends StatelessWidget {
|
class NetworkFavoritePage extends StatelessWidget {
|
||||||
const NetworkFavoritePage(this.data, {super.key});
|
const NetworkFavoritePage(this.data, {super.key});
|
||||||
|
|
||||||
@@ -14,13 +68,16 @@ class NetworkFavoritePage extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _NormalFavoritePage extends StatelessWidget {
|
class _NormalFavoritePage extends StatelessWidget {
|
||||||
const _NormalFavoritePage(this.data);
|
_NormalFavoritePage(this.data);
|
||||||
|
|
||||||
final FavoriteData data;
|
final FavoriteData data;
|
||||||
|
|
||||||
|
final comicListKey = GlobalKey<ComicListState>();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ComicList(
|
return ComicList(
|
||||||
|
key: comicListKey,
|
||||||
leadingSliver: SliverAppbar(
|
leadingSliver: SliverAppbar(
|
||||||
leading: Tooltip(
|
leading: Tooltip(
|
||||||
message: "Folders".tl,
|
message: "Folders".tl,
|
||||||
@@ -52,6 +109,20 @@ class _NormalFavoritePage extends StatelessWidget {
|
|||||||
title: Text(data.title),
|
title: Text(data.title),
|
||||||
),
|
),
|
||||||
loadPage: (i) => data.loadComic(i),
|
loadPage: (i) => data.loadComic(i),
|
||||||
|
menuBuilder: (comic) {
|
||||||
|
return [
|
||||||
|
MenuEntry(
|
||||||
|
icon: Icons.delete_outline,
|
||||||
|
text: "Remove".tl,
|
||||||
|
onClick: () async {
|
||||||
|
var res = await _deleteComic(comic.id, null, comic.sourceKey);
|
||||||
|
if (res) {
|
||||||
|
comicListKey.currentState!.remove(comic);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
];
|
||||||
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -413,7 +484,7 @@ class _CreateFolderDialogState extends State<_CreateFolderDialog> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _FavoriteFolder extends StatelessWidget {
|
class _FavoriteFolder extends StatelessWidget {
|
||||||
const _FavoriteFolder(this.data, this.folderID, this.title);
|
_FavoriteFolder(this.data, this.folderID, this.title);
|
||||||
|
|
||||||
final FavoriteData data;
|
final FavoriteData data;
|
||||||
|
|
||||||
@@ -421,13 +492,30 @@ class _FavoriteFolder extends StatelessWidget {
|
|||||||
|
|
||||||
final String title;
|
final String title;
|
||||||
|
|
||||||
|
final comicListKey = GlobalKey<ComicListState>();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ComicList(
|
return ComicList(
|
||||||
|
key: comicListKey,
|
||||||
leadingSliver: SliverAppbar(
|
leadingSliver: SliverAppbar(
|
||||||
title: Text(title),
|
title: Text(title),
|
||||||
),
|
),
|
||||||
loadPage: (i) => data.loadComic(i, folderID),
|
loadPage: (i) => data.loadComic(i, folderID),
|
||||||
|
menuBuilder: (comic) {
|
||||||
|
return [
|
||||||
|
MenuEntry(
|
||||||
|
icon: Icons.delete_outline,
|
||||||
|
text: "Remove".tl,
|
||||||
|
onClick: () async {
|
||||||
|
var res = await _deleteComic(comic.id, null, comic.sourceKey);
|
||||||
|
if (res) {
|
||||||
|
comicListKey.currentState!.remove(comic);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
];
|
||||||
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -61,13 +61,18 @@ class _LeftBarState extends State<_LeftBar> implements FolderList {
|
|||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
const CloseButton(),
|
const CloseButton(),
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
Text("Folders".tl, style: ts.s18,),
|
Text(
|
||||||
|
"Folders".tl,
|
||||||
|
style: ts.s18,
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
).paddingTop(context.padding.top),
|
).paddingTop(context.padding.top),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: ListView.builder(
|
child: ListView.builder(
|
||||||
padding: widget.withAppbar ? EdgeInsets.zero : EdgeInsets.only(top: context.padding.top),
|
padding: widget.withAppbar
|
||||||
|
? EdgeInsets.zero
|
||||||
|
: EdgeInsets.only(top: context.padding.top),
|
||||||
itemCount: folders.length + networkFolders.length + 2,
|
itemCount: folders.length + networkFolders.length + 2,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
if (index == 0) {
|
if (index == 0) {
|
||||||
@@ -76,8 +81,11 @@ class _LeftBarState extends State<_LeftBar> implements FolderList {
|
|||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
const SizedBox(width: 16),
|
const SizedBox(width: 16),
|
||||||
const Icon(Icons.local_activity),
|
Icon(
|
||||||
const SizedBox(width: 8),
|
Icons.local_activity,
|
||||||
|
color: context.colorScheme.secondary,
|
||||||
|
),
|
||||||
|
const SizedBox(width: 12),
|
||||||
Text("Local".tl),
|
Text("Local".tl),
|
||||||
const Spacer(),
|
const Spacer(),
|
||||||
IconButton(
|
IconButton(
|
||||||
@@ -103,12 +111,23 @@ class _LeftBarState extends State<_LeftBar> implements FolderList {
|
|||||||
index -= folders.length;
|
index -= folders.length;
|
||||||
if (index == 0) {
|
if (index == 0) {
|
||||||
return Container(
|
return Container(
|
||||||
padding: const EdgeInsets.symmetric(vertical: 8),
|
padding: const EdgeInsets.symmetric(vertical: 12),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
border: Border(
|
||||||
|
top: BorderSide(
|
||||||
|
color: context.colorScheme.outlineVariant,
|
||||||
|
width: 0.6,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
const SizedBox(width: 16),
|
const SizedBox(width: 16),
|
||||||
const Icon(Icons.cloud),
|
Icon(
|
||||||
const SizedBox(width: 8),
|
Icons.cloud,
|
||||||
|
color: context.colorScheme.secondary,
|
||||||
|
),
|
||||||
|
const SizedBox(width: 12),
|
||||||
Text("Network".tl),
|
Text("Network".tl),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
@@ -56,7 +56,7 @@ extension TagsTranslation on String{
|
|||||||
String get translateTagsToCN => _translateTags(this);
|
String get translateTagsToCN => _translateTags(this);
|
||||||
|
|
||||||
static String translateTag(String tag) {
|
static String translateTag(String tag) {
|
||||||
if(tag.contains(':')) {
|
if(tag.contains(':') && tag.indexOf(':') == tag.lastIndexOf(':')) {
|
||||||
var [namespace, text] = tag.split(':');
|
var [namespace, text] = tag.split(':');
|
||||||
return translationTagWithNamespace(text, namespace);
|
return translationTagWithNamespace(text, namespace);
|
||||||
} else {
|
} else {
|
||||||
|
Reference in New Issue
Block a user