Skip to content

Commit

Permalink
feat(gebura): rebuild library logic
Browse files Browse the repository at this point in the history
  • Loading branch information
MuZhou233 committed Feb 19, 2024
1 parent 4197e8e commit 439dc9b
Show file tree
Hide file tree
Showing 16 changed files with 377 additions and 76 deletions.
126 changes: 107 additions & 19 deletions lib/bloc/gebura/gebura_bloc.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,37 +26,109 @@ class GeburaBloc extends Bloc<GeburaEvent, GeburaState> {

GeburaBloc(this._api, this._repo) : super(GeburaState()) {
on<GeburaInitEvent>((event, emit) async {
if (state.purchasedAppInfos == null) {
add(GeburaPurchasedAppInfosLoadEvent());
if (state.ownedApps == null) {
add(GeburaRefreshLibraryEvent());
add(GeburaScanLocalLibraryEvent());
}
});

on<GeburaPurchasedAppInfosLoadEvent>((event, emit) async {
emit(GeburaPurchasedAppsLoadState(state, EventStatus.processing));
on<GeburaRefreshLibraryEvent>((event, emit) async {
emit(GeburaRefreshLibraryState(state, EventStatus.processing));
final resp = await _api.doRequest(
(client) => client.getPurchasedAppInfos,
GetPurchasedAppInfosRequest(),
);
if (resp.status != ApiStatus.success) {
emit(GeburaPurchasedAppsLoadState(state, EventStatus.failed,
emit(GeburaRefreshLibraryState(state, EventStatus.failed,
msg: resp.error));
return;
}
emit(GeburaPurchasedAppsLoadState(
state.copyWith(purchasedAppInfos: resp.getData().appInfos),
EventStatus.success,
msg: resp.error));
final ownedApps = <App>[];
for (var i = 0; i < 1000; i++) {
final appResp = await _api.doRequest(
(client) => client.listApps,
ListAppsRequest(
paging: PagingRequest(
pageSize: Int64(100),
pageNum: Int64(i + 1),
),
),
);
if (appResp.status != ApiStatus.success) {
emit(GeburaRefreshLibraryState(state, EventStatus.failed,
msg: resp.error));
return;
}
if (appResp.getData().appPackages.isEmpty) {
break;
}
ownedApps.addAll(appResp.getData().appPackages);
}
emit(GeburaRefreshLibraryState(
state.copyWith(
purchasedAppInfos: resp.getData().appInfos,
ownedApps: ownedApps,
),
EventStatus.success,
msg: resp.error,
));
add(GeburaApplyLibrarySettingsEvent());
}, transformer: droppable());

on<GeburaSetPurchasedAppInfoIndexEvent>((event, emit) async {
on<GeburaApplyLibrarySettingsEvent>((event, emit) async {
var settings =
state.librarySettings ?? const LibrarySettings(query: null);
if (event.usePreviousSettings == null || !event.usePreviousSettings!) {
settings = settings.copyWith(query: event.query);
}
// prepare library items
Map<Int64, AppInfoMixed> libraryItemMap = Map.fromEntries(
(state.purchasedAppInfos ?? []).map((e) => MapEntry(e.id.id, e)),
);
final appInfoMap = state.appInfoMap ?? {};
for (final App app in state.ownedApps ?? []) {
if (app.hasAssignedAppInfoId()) {
if (appInfoMap[app.assignedAppInfoId.id] != null) {
libraryItemMap[app.assignedAppInfoId.id] =
appInfoToMixed(mixAppInfo(
appInfoMap[app.assignedAppInfoId.id]!,
));
} else {
add(GeburaFetchBoundAppInfosEvent(app.assignedAppInfoId));
}
} else {
libraryItemMap[app.id.id] = AppInfoMixed(
id: app.id,
name: app.name,
shortDescription: app.description,
);
}
}
// apply query
if (settings.query != null && settings.query!.isNotEmpty) {
final query = settings.query!.toLowerCase();
libraryItemMap = Map.fromEntries(libraryItemMap.entries.where(
(element) => element.value.name.toLowerCase().contains(query),
));
}
// sort by name
libraryItemMap = Map.fromEntries(libraryItemMap.entries.toList()
..sort((a, b) => a.value.name.compareTo(b.value.name)));
// emit
emit(state.copyWith(
libraryItems: libraryItemMap.values.toList(),
librarySettings: settings,
));
});

on<GeburaSetSelectedLibraryItemEvent>((event, emit) async {
final newState = state.copyWith();
newState.selectedPurchasedAppInfoIndex = event.index;
newState.selectedLibraryItem = event.id?.id.toInt();
emit(newState);
});

on<GeburaSearchAppInfosEvent>((event, emit) async {
emit(GeburaSearchAppsState(state, EventStatus.processing));
emit(GeburaSearchAppInfosState(state, EventStatus.processing));
final resp = await _api.doRequest(
(client) => client.searchAppInfos,
SearchAppInfosRequest(
Expand All @@ -68,10 +140,11 @@ class GeburaBloc extends Bloc<GeburaEvent, GeburaState> {
),
);
if (resp.status != ApiStatus.success) {
emit(GeburaSearchAppsState(state, EventStatus.failed, msg: resp.error));
emit(GeburaSearchAppInfosState(state, EventStatus.failed,
msg: resp.error));
return;
}
emit(GeburaSearchAppsState(
emit(GeburaSearchAppInfosState(
state,
EventStatus.success,
msg: resp.error,
Expand All @@ -95,7 +168,7 @@ class GeburaBloc extends Bloc<GeburaEvent, GeburaState> {
return;
}
emit(GeburaPurchaseState(state, EventStatus.success, msg: resp.error));
add(GeburaPurchasedAppInfosLoadEvent());
add(GeburaRefreshLibraryEvent());
}, transformer: droppable());

on<GeburaSetAppLauncherSettingEvent>((event, emit) async {
Expand Down Expand Up @@ -334,7 +407,7 @@ class GeburaBloc extends Bloc<GeburaEvent, GeburaState> {
));
}
await _repo.setImportedSteamApps(importedSteamApps);
add(GeburaPurchasedAppInfosLoadEvent());
add(GeburaRefreshLibraryEvent());
emit(GeburaImportSteamAppsState(
state.copyWith(
localLibraryState: S.current.importSteamApplicationFinished(
Expand All @@ -357,10 +430,10 @@ class GeburaBloc extends Bloc<GeburaEvent, GeburaState> {
msg: resp.error));
return;
}
final storeApps = state.storeAppInfos ?? {};
storeApps[event.appID] = resp.getData().appInfos;
final appInfoMap = state.appInfoMap ?? {};
appInfoMap[event.appID.id] = resp.getData().appInfos;
emit(GeburaFetchBoundAppsState(
state.copyWith(storeAppInfos: storeApps),
state.copyWith(appInfoMap: appInfoMap),
EventStatus.success,
msg: resp.error,
));
Expand Down Expand Up @@ -439,3 +512,18 @@ AppInfo mixAppInfo(List<AppInfo> apps) {
}
return mixedApp;
}

AppInfoMixed appInfoToMixed(AppInfo appInfo) {
return AppInfoMixed(
id: appInfo.id,
name: appInfo.name,
type: appInfo.type,
shortDescription: appInfo.shortDescription,
iconImageUrl: appInfo.iconImageUrl,
backgroundImageUrl: appInfo.backgroundImageUrl,
coverImageUrl: appInfo.coverImageUrl,
tags: appInfo.tags,
altNames: appInfo.altNames,
details: appInfo.details,
);
}
15 changes: 11 additions & 4 deletions lib/bloc/gebura/gebura_event.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,19 @@ sealed class GeburaEvent {}

final class GeburaInitEvent extends GeburaEvent {}

final class GeburaPurchasedAppInfosLoadEvent extends GeburaEvent {}
final class GeburaRefreshLibraryEvent extends GeburaEvent {}

final class GeburaSetPurchasedAppInfoIndexEvent extends GeburaEvent {
final int? index;
final class GeburaApplyLibrarySettingsEvent extends GeburaEvent {
final String? query;
final bool? usePreviousSettings;

GeburaSetPurchasedAppInfoIndexEvent(this.index);
GeburaApplyLibrarySettingsEvent({this.query, this.usePreviousSettings});
}

final class GeburaSetSelectedLibraryItemEvent extends GeburaEvent {
final InternalID? id;

GeburaSetSelectedLibraryItemEvent(this.id);
}

final class GeburaSearchAppInfosEvent extends GeburaEvent {
Expand Down
44 changes: 29 additions & 15 deletions lib/bloc/gebura/gebura_state.dart
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
part of 'gebura_bloc.dart';

class GeburaState {
late Map<Int64, List<AppInfo>>? appInfoMap;
late List<AppInfoMixed>? purchasedAppInfos;
late int? selectedPurchasedAppInfoIndex;
late List<App>? ownedApps;
late List<AppInfoMixed>? libraryItems;
late LibrarySettings? librarySettings;
late int? selectedLibraryItem;

late Map<InternalID, List<AppInfo>>? storeAppInfos;
late Map<InternalID, AppRunState>? runState;

late String? localLibraryState;
Expand All @@ -14,9 +17,12 @@ class GeburaState {
late List<String>? localSteamLibraryFolders;

GeburaState({
this.appInfoMap,
this.purchasedAppInfos,
this.selectedPurchasedAppInfoIndex,
this.storeAppInfos,
this.ownedApps,
this.libraryItems,
this.librarySettings,
this.selectedLibraryItem,
this.runState,
this.localLibraryState,
this.localSteamScanResult,
Expand All @@ -26,9 +32,12 @@ class GeburaState {
});

GeburaState copyWith({
Map<Int64, List<AppInfo>>? appInfoMap,
List<AppInfoMixed>? purchasedAppInfos,
int? selectedPurchasedAppInfoIndex,
Map<InternalID, List<AppInfo>>? storeAppInfos,
List<App>? ownedApps,
List<AppInfoMixed>? libraryItems,
LibrarySettings? librarySettings,
int? selectedLibraryItem,
Map<InternalID, AppRunState>? runState,
String? localLibraryState,
SteamScanResult? localSteamScanResult,
Expand All @@ -37,10 +46,12 @@ class GeburaState {
List<String>? localSteamLibraryFolders,
}) {
return GeburaState(
appInfoMap: appInfoMap ?? this.appInfoMap,
purchasedAppInfos: purchasedAppInfos ?? this.purchasedAppInfos,
selectedPurchasedAppInfoIndex:
selectedPurchasedAppInfoIndex ?? this.selectedPurchasedAppInfoIndex,
storeAppInfos: storeAppInfos ?? this.storeAppInfos,
ownedApps: ownedApps ?? this.ownedApps,
libraryItems: libraryItems ?? this.libraryItems,
librarySettings: librarySettings ?? this.librarySettings,
selectedLibraryItem: selectedLibraryItem ?? this.selectedLibraryItem,
runState: runState ?? this.runState,
localLibraryState: localLibraryState ?? this.localLibraryState,
localSteamScanResult: localSteamScanResult ?? this.localSteamScanResult,
Expand All @@ -52,9 +63,12 @@ class GeburaState {
}

void _from(GeburaState other) {
appInfoMap = other.appInfoMap;
purchasedAppInfos = other.purchasedAppInfos;
selectedPurchasedAppInfoIndex = other.selectedPurchasedAppInfoIndex;
storeAppInfos = other.storeAppInfos;
ownedApps = other.ownedApps;
libraryItems = other.libraryItems;
librarySettings = other.librarySettings;
selectedLibraryItem = other.selectedLibraryItem;
runState = other.runState;
localLibraryState = other.localLibraryState;
localSteamScanResult = other.localSteamScanResult;
Expand All @@ -64,8 +78,8 @@ class GeburaState {
}
}

class GeburaPurchasedAppsLoadState extends GeburaState with EventStatusMixin {
GeburaPurchasedAppsLoadState(GeburaState state, this.statusCode, {this.msg})
class GeburaRefreshLibraryState extends GeburaState with EventStatusMixin {
GeburaRefreshLibraryState(GeburaState state, this.statusCode, {this.msg})
: super() {
_from(state);
}
Expand All @@ -76,8 +90,8 @@ class GeburaPurchasedAppsLoadState extends GeburaState with EventStatusMixin {
final String? msg;
}

class GeburaSearchAppsState extends GeburaState with EventStatusMixin {
GeburaSearchAppsState(GeburaState state, this.statusCode,
class GeburaSearchAppInfosState extends GeburaState with EventStatusMixin {
GeburaSearchAppInfosState(GeburaState state, this.statusCode,
{this.msg, this.apps})
: super() {
_from(state);
Expand Down
2 changes: 2 additions & 0 deletions lib/consts.dart
Original file line number Diff line number Diff line change
Expand Up @@ -109,3 +109,5 @@ class DotEnvValue {
static String port = dotenv.env['PORT'] ?? '';
static String tls = dotenv.env['TLS'] ?? '';
}

const wellKnownAccountPlatforms = ['steam'];
2 changes: 1 addition & 1 deletion lib/model/common_model.freezed.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ part of 'common_model.dart';
T _$identity<T>(T value) => value;

final _privateConstructorUsedError = UnsupportedError(
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods');
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models');

ServerConfig _$ServerConfigFromJson(Map<String, dynamic> json) {
return _ServerConfig.fromJson(json);
Expand Down
10 changes: 10 additions & 0 deletions lib/model/gebura_model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,13 @@ class ImportedSteamApp with _$ImportedSteamApp {
factory ImportedSteamApp.fromJson(Map<String, Object?> json) =>
_$ImportedSteamAppFromJson(json);
}

@freezed
class LibrarySettings with _$LibrarySettings {
const factory LibrarySettings({
required String? query,
}) = _LibrarySettings;

factory LibrarySettings.fromJson(Map<String, Object?> json) =>
_$LibrarySettingsFromJson(json);
}
Loading

0 comments on commit 439dc9b

Please sign in to comment.