Skip to content

Commit

Permalink
feat(gebura): add assign app panel
Browse files Browse the repository at this point in the history
  • Loading branch information
MuZhou233 committed Mar 11, 2024
1 parent cbf3270 commit 02471db
Show file tree
Hide file tree
Showing 6 changed files with 343 additions and 16 deletions.
82 changes: 82 additions & 0 deletions lib/bloc/gebura/gebura_bloc.dart
Original file line number Diff line number Diff line change
Expand Up @@ -641,6 +641,88 @@ class GeburaBloc extends Bloc<GeburaEvent, GeburaState> {
));
add(GeburaRefreshLibraryEvent());
});

on<GeburaSearchNewAppInfoEvent>((event, emit) async {
emit(GeburaSearchNewAppInfoState(state, EventStatus.processing));
final resp = await _api.doRequest(
(client) => client.searchNewAppInfos,
SearchNewAppInfosRequest(
paging: PagingRequest(
pageSize: Int64(10),
pageNum: Int64(1),
),
name: event.query,
),
);
if (resp.status != ApiStatus.success) {
emit(GeburaSearchNewAppInfoState(state, EventStatus.failed,
msg: resp.error));
return;
}
emit(GeburaSearchNewAppInfoState(
state,
EventStatus.success,
msg: resp.error,
infos: resp.getData().appInfos,
));
}, transformer: droppable());

on<GeburaAssignAppWithNewInfoEvent>((event, emit) async {
emit(GeburaAssignAppInfoState(state, EventStatus.processing));
final syncResp = await _api.doRequest(
(client) => client.syncAppInfos,
SyncAppInfosRequest(
appInfoIds: [
AppInfoID(
internal: false,
source: event.appInfoSource,
sourceAppId: event.appInfoSourceID)
],
waitData: true,
));
if (syncResp.status != ApiStatus.success) {
emit(GeburaAssignAppInfoState(state, EventStatus.failed,
msg: syncResp.error));
return;
}
final boundInfoResp = await _api.doRequest(
(client) => client.getBoundAppInfos,
GetBoundAppInfosRequest(
appInfoId: syncResp.getData().appInfos.first.id,
));
if (boundInfoResp.status != ApiStatus.success) {
emit(GeburaAssignAppInfoState(state, EventStatus.failed,
msg: boundInfoResp.error));
return;
}
if (!boundInfoResp
.getData()
.appInfos
.any((element) => element.internal)) {
emit(GeburaAssignAppInfoState(state, EventStatus.failed,
msg: 'No internal app info found'));
}
final appInfoId = boundInfoResp
.getData()
.appInfos
.firstWhere((element) => element.internal)
.id;
final resp = await _api.doRequest(
(client) => client.assignApp,
AssignAppRequest(
appInfoId: appInfoId,
appId: event.appID,
),
);
if (resp.status != ApiStatus.success) {
emit(GeburaAssignAppInfoState(state, EventStatus.failed,
msg: resp.error));
return;
}
emit(GeburaAssignAppInfoState(state, EventStatus.success,
msg: resp.error));
add(GeburaRefreshLibraryEvent());
}, transformer: droppable());
}

LocalAppInstLauncherSetting? getAppLauncherSetting(InternalID id) {
Expand Down
15 changes: 15 additions & 0 deletions lib/bloc/gebura/gebura_event.dart
Original file line number Diff line number Diff line change
Expand Up @@ -124,3 +124,18 @@ final class GeburaRefreshAppInfoEvent extends GeburaEvent {

GeburaRefreshAppInfoEvent(this.appInfoID);
}

final class GeburaAssignAppWithNewInfoEvent extends GeburaEvent {
final InternalID appID;
final String appInfoSource;
final String appInfoSourceID;

GeburaAssignAppWithNewInfoEvent(
this.appID, this.appInfoSource, this.appInfoSourceID);
}

final class GeburaSearchNewAppInfoEvent extends GeburaEvent {
final String query;

GeburaSearchNewAppInfoEvent(this.query);
}
27 changes: 27 additions & 0 deletions lib/bloc/gebura/gebura_state.dart
Original file line number Diff line number Diff line change
Expand Up @@ -288,3 +288,30 @@ class GeburaRefreshAppInfoState extends GeburaState with EventStatusMixin {
@override
final String? msg;
}

class GeburaAssignAppInfoState extends GeburaState with EventStatusMixin {
GeburaAssignAppInfoState(GeburaState state, this.statusCode, {this.msg})
: super() {
_from(state);
}

@override
final EventStatus? statusCode;
@override
final String? msg;
}

class GeburaSearchNewAppInfoState extends GeburaState with EventStatusMixin {
GeburaSearchNewAppInfoState(GeburaState state, this.statusCode,
{this.infos, this.msg})
: super() {
_from(state);
}

final List<AppInfo>? infos;

@override
final EventStatus? statusCode;
@override
final String? msg;
}
14 changes: 14 additions & 0 deletions lib/route.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import 'repo/grpc/api_helper.dart';
import 'view/layout/overlapping_panels.dart';
import 'view/pages/chesed/chesed_home_page.dart';
import 'view/pages/frame_page.dart';
import 'view/pages/gebura/gebura_assign_app_panel.dart';
import 'view/pages/gebura/gebura_library_detail.dart';
import 'view/pages/gebura/gebura_library_overview.dart';
import 'view/pages/gebura/gebura_library_settings.dart';
Expand Down Expand Up @@ -135,6 +136,9 @@ class AppRoutes {
AppRoutes._('$_gebura/${GeburaFunctions.librarySettings}');
static AppRoutes geburaLibraryDetail(int id) =>
AppRoutes._('$geburaLibrary?id=$id');
static AppRoutes geburaLibraryAssignApp(int id) =>
AppRoutes._('$geburaLibrary?id=$id&action=${_GeburaActions.assignApp}',
isAction: true);

static const String _chesed = '$_module/${ModuleName._chesed}';
static const AppRoutes chesed = AppRoutes._(_chesed);
Expand Down Expand Up @@ -238,6 +242,10 @@ class GeburaFunctions {
static const String librarySettings = 'librarySettings';
}

class _GeburaActions {
static const String assignApp = 'assignApp';
}

class _SettingsFunctions {
static const String client = 'client';
static const String notifyTarget = 'notifyTarget';
Expand Down Expand Up @@ -438,12 +446,17 @@ GoRouter getRouter(MainBloc mainBloc, ApiHelper apiHelper) {
pageBuilder: (context, state) {
final function = state.pathParameters['function'] ??
AppRoutes.geburaStore.toString();
final action = state.uri.queryParameters['action'] ??
_GeburaActions.assignApp;
final geburaPages = {
GeburaFunctions.store: const GeburaStorePage(),
GeburaFunctions.library: const GeburaLibraryOverview(),
GeburaFunctions.librarySettings:
const GeburaLibrarySettings(),
};
final geburaActions = {
_GeburaActions.assignApp: const GeburaAssignAppPanel(),
};
Widget? page = geburaPages[function];
if (state.uri.queryParameters['id']?.isNotEmpty ?? false) {
final idStr = state.uri.queryParameters['id'] ?? '';
Expand All @@ -461,6 +474,7 @@ GoRouter getRouter(MainBloc mainBloc, ApiHelper apiHelper) {
function: function,
),
middlePart: page,
rightPart: geburaActions[action],
),
),
);
Expand Down
193 changes: 193 additions & 0 deletions lib/view/pages/gebura/gebura_assign_app_panel.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:tuihub_protos/librarian/v1/common.pb.dart';

import '../../../../route.dart';
import '../../../bloc/gebura/gebura_bloc.dart';
import '../../components/toast.dart';
import '../../specialized/right_panel_form.dart';

class GeburaAssignAppPanel extends StatefulWidget {
const GeburaAssignAppPanel({super.key});

@override
State<StatefulWidget> createState() => _GeburaAssignAppPanelState();
}

class _GeburaAssignAppPanelState extends State<GeburaAssignAppPanel> {
void close(BuildContext context) {
AppRoutes.geburaLibraryAssignApp(0).pop(context);
}

int _index = 0;
List<AppInfo>? searchResults;
String? searchMsg;
AppInfo? selectedAppInfo;
final TextEditingController _searchController = TextEditingController();

@override
Widget build(BuildContext context) {
return BlocConsumer<GeburaBloc, GeburaState>(
listener: (context, state) {
if (state is GeburaSearchNewAppInfoState) {
setState(() {
if (state.success) {
searchResults = state.infos;
if (searchResults?.isNotEmpty ?? false) {
searchMsg = null;
} else {
searchMsg = '无结果';
}
} else if (state.processing) {
searchMsg = '加载中';
} else if (state.failed) {
searchMsg = '加载失败,${state.msg}';
} else {
searchMsg = '无结果';
}
});
}
if (state is GeburaAssignAppInfoState && state.success) {
const Toast(title: '', message: '设置成功').show(context);
close(context);
}
},
builder: (context, state) {
final app =
state.selectedLibraryItem != null && state.libraryItems != null
? state.libraryItems!.firstWhere((element) =>
element.id.id.toInt() == state.selectedLibraryItem!)
: null;
return RightPanelForm(
title: const Text('设置应用信息'),
formFields: [
Stepper(
currentStep: _index,
onStepCancel: () {
if (_index > 0) {
setState(() {
_index -= 1;
});
}
},
onStepContinue: () {
if (_index <= 1) {
setState(() {
_index += 1;
});
}
},
onStepTapped: (int index) {
setState(() {
_index = index;
});
},
steps: <Step>[
Step(
title: const Text('应用'),
content: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
const SizedBox(
height: 8,
),
TextFormField(
initialValue: app?.name,
decoration: const InputDecoration(
border: OutlineInputBorder(),
label: Text('名称'),
),
),
],
),
),
Step(
title: const Text('查找应用信息'),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
const SizedBox(
height: 8,
),
TextFormField(
controller: _searchController,
decoration: InputDecoration(
border: const OutlineInputBorder(),
label: const Text('搜索'),
suffixIcon: IconButton(
icon: const Icon(Icons.search),
onPressed: () {
context
.read<GeburaBloc>()
.add(GeburaSearchNewAppInfoEvent(
_searchController.text,
));
},
),
),
onChanged: (value) {
context
.read<GeburaBloc>()
.add(GeburaSearchNewAppInfoEvent(
value,
));
},
),
const SizedBox(
height: 8,
),
ListView(shrinkWrap: true, children: [
if (searchMsg != null)
Padding(
padding: const EdgeInsets.all(8),
child: Text(searchMsg!),
)
else if (searchResults != null)
for (final info in searchResults!)
ListTile(
title: Text(info.name),
subtitle: Text(info.source),
onTap: () {
setState(() {
selectedAppInfo = info;
_index += 1;
});
},
),
]),
],
),
),
Step(
title: const Text('确认'),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
const SizedBox(
height: 8,
),
Text('受影响的应用: ${app?.name}'),
Text('新应用信息: ${selectedAppInfo?.name}'),
],
),
),
],
),
],
errorMsg: state is GeburaAssignAppInfoState && state.failed
? state.msg
: null,
onSubmit: () {
context.read<GeburaBloc>().add(GeburaAssignAppWithNewInfoEvent(
app!.id,
selectedAppInfo!.source,
selectedAppInfo!.sourceAppId,
));
},
submitting: state is GeburaAssignAppInfoState && state.processing,
close: () => close(context),
);
},
);
}
}
Loading

0 comments on commit 02471db

Please sign in to comment.