feat: activity page

This commit is contained in:
Simon Ding
2024-07-13 17:23:27 +08:00
parent 01408cdd89
commit 85f8750908
11 changed files with 178 additions and 22 deletions

View File

@@ -1,11 +1,51 @@
import 'dart:js_interop_unsafe';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:ui/providers/activity.dart';
class ActivityPage extends ConsumerWidget {
static const route = "/activities";
@override
Widget build(BuildContext context, WidgetRef ref) {
// TODO: implement build
throw UnimplementedError();
var activitiesWatcher = ref.watch(activitiesDataProvider);
return activitiesWatcher.when(
data: (activities) {
return SingleChildScrollView(
child: DataTable(
columns: const [
DataColumn(label: Text("id"), numeric: true),
DataColumn(label: Text("名称")),
// DataColumn(label: Text("目标路径")),
DataColumn(label: Text("是否完成")),
DataColumn(label: Text("后台操作")),
DataColumn(label: Text("操作"))
],
rows: List<DataRow>.generate(activities.length, (i) {
var activity = activities[i];
return DataRow(cells: [
DataCell(Text("${activity.id}")),
DataCell(Text("${activity.sourceTitle}")),
//DataCell(Text("${activity.targetDir}")),
DataCell(Text("${activity.completed}")),
DataCell(Text("${activity.inBackgroud}")),
DataCell(IconButton(
onPressed: () {
ref
.read(activitiesDataProvider.notifier)
.deleteActivity(activity.id!);
},
icon: const Icon(Icons.delete)))
]);
}),
),
);
},
error: (err, trace) => Text("$err"),
loading: () => const Center(
child: SizedBox(
width: 30, height: 30, child: CircularProgressIndicator())));
}
}
}

View File

@@ -1,6 +1,8 @@
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import 'package:ui/activity.dart';
import 'package:ui/login_page.dart';
import 'package:ui/navdrawer.dart';
import 'package:ui/providers/APIs.dart';
@@ -34,12 +36,19 @@ class MyApp extends StatelessWidget {
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
// Here we take the value from the MyHomePage object that was created by
// the App.build method, and use it to set our appbar title.
title: const Text("Polaris追剧"),
title: Row(
children: [
const Text("Polaris 追剧"),
const SizedBox(
width: 100,
),
IconButton(
tooltip: "搜索剧集",
onPressed: () => context.go(SearchPage.route),
icon: const Icon(Icons.search)),
],
),
actions: [
IconButton(
tooltip: "搜索剧集",
onPressed: () => context.go(SearchPage.route),
icon: const Icon(Icons.search)),
IconButton(
onPressed: () => context.go(SystemSettingsPage.route),
icon: const Icon(Icons.settings))
@@ -77,6 +86,10 @@ class MyApp extends StatelessWidget {
builder: (context, state) =>
TvDetailsPage(seriesId: state.pathParameters['id']!),
),
GoRoute(
path: ActivityPage.route,
builder: (context, state) => ActivityPage(),
)
],
);
@@ -87,7 +100,7 @@ class MyApp extends StatelessWidget {
_shellRoute,
GoRoute(
path: LoginScreen.route,
builder: (context, state) =>const LoginScreen(),
builder: (context, state) => const LoginScreen(),
)
],
);

View File

@@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:ui/activity.dart';
import 'package:ui/search.dart';
import 'package:ui/system_settings.dart';
import 'package:ui/weclome.dart';
@@ -34,7 +35,7 @@ class _NavDrawerState extends State<NavDrawer> {
if (value == 0) {
context.go(WelcomePage.route);
} else if (value == 1) {
context.go(SearchPage.route);
context.go(ActivityPage.route);
} else if (value == 2) {
context.go(SystemSettingsPage.route);
}

View File

@@ -20,6 +20,7 @@ class APIs {
static final storageUrl = "$_baseUrl/api/v1/storage/";
static final loginUrl = "$_baseUrl/api/login";
static final loginSettingUrl = "$_baseUrl/api/v1/setting/auth";
static final activityUrl = "$_baseUrl/api/v1/activity/";
static const tmdbImgBaseUrl = "https://image.tmdb.org/t/p/w500/";

View File

@@ -0,0 +1,74 @@
import 'dart:async';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:ui/providers/APIs.dart';
import 'package:ui/providers/server_response.dart';
var activitiesDataProvider = AsyncNotifierProvider.autoDispose<ActivityData, List<Activity>>(
ActivityData.new);
class ActivityData extends AutoDisposeAsyncNotifier<List<Activity>> {
@override
FutureOr<List<Activity>> build() async {
final dio = await APIs.getDio();
var resp = await dio.get(APIs.activityUrl);
final sp = ServerResponse.fromJson(resp.data);
if (sp.code != 0) {
throw sp.message;
}
List<Activity> activities = List.empty(growable: true);
for (final a in sp.data as List) {
activities.add(Activity.fromJson(a));
}
return activities;
}
Future<void> deleteActivity(int id) async {
final dio = await APIs.getDio();
var resp = await dio.delete("${APIs.activityUrl}$id");
final sp = ServerResponse.fromJson(resp.data);
if (sp.code != 0) {
throw sp.message;
}
ref.invalidateSelf();
}
}
class Activity {
Activity({
required this.id,
required this.seriesId,
required this.episodeId,
required this.sourceTitle,
required this.date,
required this.targetDir,
required this.completed,
required this.saved,
required this.inBackgroud,
});
final int? id;
final int? seriesId;
final int? episodeId;
final String? sourceTitle;
final DateTime? date;
final String? targetDir;
final bool? completed;
final String? saved;
final bool? inBackgroud;
factory Activity.fromJson(Map<String, dynamic> json){
return Activity(
id: json["id"],
seriesId: json["series_id"],
episodeId: json["episode_id"],
sourceTitle: json["source_title"],
date: DateTime.tryParse(json["date"] ?? ""),
targetDir: json["target_dir"],
completed: json["completed"],
saved: json["saved"],
inBackgroud: json["in_backgroud"],
);
}
}