Don't try to query ncalbum when Nextcloud <25

This commit is contained in:
Ming Ming 2023-05-11 00:42:56 +08:00
parent 499583d76f
commit 2b177d7679
16 changed files with 215 additions and 19 deletions

View file

@ -7,6 +7,7 @@ import 'package:nc_photos/entity/file.dart';
import 'package:nc_photos/entity/nc_album.dart';
import 'package:nc_photos/entity/nc_album_item.dart';
import 'package:nc_photos/entity/person.dart';
import 'package:nc_photos/entity/server_status.dart';
import 'package:nc_photos/entity/share.dart';
import 'package:nc_photos/entity/sharee.dart';
import 'package:nc_photos/entity/tag.dart';
@ -179,6 +180,16 @@ class ApiShareeConverter {
};
}
class ApiStatusConverter {
static ServerStatus fromApi(api.Status status) {
return ServerStatus(
versionRaw: status.version,
versionName: status.versionString,
productName: status.productName,
);
}
}
class ApiTagConverter {
static Tag fromApi(api.Tag tag) {
return Tag(

View file

@ -5,6 +5,7 @@ import 'package:kiwi/kiwi.dart';
import 'package:logging/logging.dart';
import 'package:nc_photos/account.dart';
import 'package:nc_photos/controller/collections_controller.dart';
import 'package:nc_photos/controller/server_controller.dart';
import 'package:nc_photos/di_container.dart';
import 'package:nc_photos/entity/collection.dart';
import 'package:nc_photos/entity/person.dart';
@ -126,7 +127,8 @@ class HomeSearchSuggestionBlocFailure extends HomeSearchSuggestionBlocState {
@npLog
class HomeSearchSuggestionBloc
extends Bloc<HomeSearchSuggestionBlocEvent, HomeSearchSuggestionBlocState> {
HomeSearchSuggestionBloc(this.account, this.collectionsController)
HomeSearchSuggestionBloc(
this.account, this.collectionsController, this.serverController)
: super(const HomeSearchSuggestionBlocInit()) {
final c = KiwiContainer().resolve<DiContainer>();
assert(require(c));
@ -194,7 +196,9 @@ class HomeSearchSuggestionBloc
.map((e) => e.collection)
.toList();
if (collections.isEmpty) {
collections = await ListCollection(_c)(account).last;
collections = await ListCollection(_c,
serverController: serverController)(account)
.last;
}
product.addAll(collections.map(_CollectionSearcheable.new));
_log.info(
@ -247,6 +251,7 @@ class HomeSearchSuggestionBloc
final Account account;
final CollectionsController collectionsController;
final ServerController serverController;
late final DiContainer _c;
final _search = Woozy<_Searcheable>(limit: 10);

View file

@ -1,6 +1,7 @@
import 'package:kiwi/kiwi.dart';
import 'package:nc_photos/account.dart';
import 'package:nc_photos/controller/collections_controller.dart';
import 'package:nc_photos/controller/server_controller.dart';
import 'package:nc_photos/di_container.dart';
class AccountController {
@ -8,6 +9,7 @@ class AccountController {
_account = account;
_collectionsController?.dispose();
_collectionsController = null;
_serverController = null;
}
Account get account => _account!;
@ -16,8 +18,15 @@ class AccountController {
_collectionsController ??= CollectionsController(
KiwiContainer().resolve<DiContainer>(),
account: _account!,
serverController: serverController,
);
ServerController get serverController =>
_serverController ??= ServerController(
account: _account!,
);
Account? _account;
CollectionsController? _collectionsController;
ServerController? _serverController;
}

View file

@ -6,6 +6,7 @@ import 'package:logging/logging.dart';
import 'package:mutex/mutex.dart';
import 'package:nc_photos/account.dart';
import 'package:nc_photos/controller/collection_items_controller.dart';
import 'package:nc_photos/controller/server_controller.dart';
import 'package:nc_photos/di_container.dart';
import 'package:nc_photos/entity/collection.dart';
import 'package:nc_photos/entity/collection/util.dart';
@ -64,6 +65,7 @@ class CollectionsController {
CollectionsController(
this._c, {
required this.account,
required this.serverController,
});
void dispose() {
@ -264,7 +266,7 @@ class CollectionsController {
hasNext: false,
);
final completer = Completer();
ListCollection(_c)(account).listen(
ListCollection(_c, serverController: serverController)(account).listen(
(c) {
lastData = CollectionStreamEvent(
data: _prepareDataFor(c),
@ -325,6 +327,7 @@ class CollectionsController {
final DiContainer _c;
final Account account;
final ServerController serverController;
var _isDataStreamInited = false;
final _dataStreamController = BehaviorSubject.seeded(

View file

@ -0,0 +1,49 @@
import 'dart:async';
import 'package:logging/logging.dart';
import 'package:nc_photos/account.dart';
import 'package:nc_photos/api/entity_converter.dart';
import 'package:nc_photos/entity/server_status.dart';
import 'package:nc_photos/np_api_util.dart';
import 'package:np_api/np_api.dart' as api;
import 'package:np_codegen/np_codegen.dart';
import 'package:rxdart/rxdart.dart';
part 'server_controller.g.dart';
@npLog
class ServerController {
ServerController({
required this.account,
});
ValueStream<ServerStatus> get status {
if (!_statusStreamContorller.hasValue) {
unawaited(_load());
}
return _statusStreamContorller.stream;
}
Future<void> _load() => _getStatus();
Future<void> _getStatus() async {
try {
final response = await ApiUtil.fromAccount(account).status().get();
if (!response.isGood) {
_log.severe("[_getStatus] Failed requesting server: $response");
return;
}
final apiStatus = await api.StatusParser().parse(response.body);
final status = ApiStatusConverter.fromApi(apiStatus);
_log.info("[_getStatus] Server status: $status");
_statusStreamContorller.add(status);
} catch (e, stackTrace) {
_log.severe("[_getStatus] Failed while get", e, stackTrace);
return;
}
}
final Account account;
final _statusStreamContorller = BehaviorSubject<ServerStatus>();
}

View file

@ -0,0 +1,14 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'server_controller.dart';
// **************************************************************************
// NpLogGenerator
// **************************************************************************
extension _$ServerControllerNpLog on ServerController {
// ignore: unused_element
Logger get _log => log;
static final log = Logger("controller.server_controller.ServerController");
}

View file

@ -0,0 +1,24 @@
import 'package:to_string/to_string.dart';
part 'server_status.g.dart';
@toString
class ServerStatus {
const ServerStatus({
required this.versionRaw,
required this.versionName,
required this.productName,
});
@override
String toString() => _$toString();
final String versionRaw;
final String versionName;
final String productName;
}
extension ServerStatusExtension on ServerStatus {
List<int> get versionNumber => versionRaw.split(".").map(int.parse).toList();
int get majorVersion => versionNumber[0];
}

View file

@ -0,0 +1,14 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'server_status.dart';
// **************************************************************************
// ToStringGenerator
// **************************************************************************
extension _$ServerStatusToString on ServerStatus {
String _$toString() {
// ignore: unnecessary_string_interpolations
return "ServerStatus {versionRaw: $versionRaw, versionName: $versionName, productName: $productName}";
}
}

View file

@ -1,16 +1,21 @@
import 'dart:async';
import 'package:nc_photos/account.dart';
import 'package:nc_photos/controller/server_controller.dart';
import 'package:nc_photos/di_container.dart';
import 'package:nc_photos/entity/album.dart';
import 'package:nc_photos/entity/collection.dart';
import 'package:nc_photos/entity/collection/builder.dart';
import 'package:nc_photos/entity/nc_album.dart';
import 'package:nc_photos/entity/server_status.dart';
import 'package:nc_photos/use_case/album/list_album2.dart';
import 'package:nc_photos/use_case/nc_album/list_nc_album.dart';
class ListCollection {
ListCollection(this._c) : assert(require(_c));
ListCollection(
this._c, {
required this.serverController,
}) : assert(require(_c));
static bool require(DiContainer c) =>
DiContainer.has(c, DiType.albumRepo2) &&
@ -51,23 +56,29 @@ class ListCollection {
onDone();
},
);
ListNcAlbum(_c)(account).listen(
(event) {
ncAlbums = event;
notify();
},
onDone: () {
isNcAlbumDone = true;
onDone();
},
onError: (e, stackTrace) {
controller.addError(e, stackTrace);
isNcAlbumDone = true;
onDone();
},
);
if (serverController.status.hasValue &&
serverController.status.value.majorVersion < 25) {
isNcAlbumDone = true;
} else {
ListNcAlbum(_c)(account).listen(
(event) {
ncAlbums = event;
notify();
},
onDone: () {
isNcAlbumDone = true;
onDone();
},
onError: (e, stackTrace) {
controller.addError(e, stackTrace);
isNcAlbumDone = true;
onDone();
},
);
}
return controller.stream;
}
final DiContainer _c;
final ServerController serverController;
}

View file

@ -1,9 +1,13 @@
import 'dart:async';
import 'package:event_bus/event_bus.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:kiwi/kiwi.dart';
import 'package:logging/logging.dart';
import 'package:nc_photos/account.dart';
import 'package:nc_photos/app_localizations.dart';
import 'package:nc_photos/controller/account_controller.dart';
import 'package:nc_photos/di_container.dart';
import 'package:nc_photos/entity/album.dart';
import 'package:nc_photos/entity/album/data_source.dart';
@ -64,6 +68,16 @@ class _HomeState extends State<Home> with TickerProviderStateMixin {
});
}
_animationController.value = 1;
// call once to pre-cache the value
unawaited(context
.read<AccountController>()
.serverController
.status
.first
.then((value) {
_log.info("Server status: $value");
}));
}
@override

View file

@ -79,6 +79,7 @@ class _HomeSearchSuggestionState extends State<HomeSearchSuggestion>
_bloc = (widget.controller._bloc ??= HomeSearchSuggestionBloc(
widget.account,
context.read<AccountController>().collectionsController,
context.read<AccountController>().serverController,
));
if (_bloc.state is! HomeSearchSuggestionBlocInit) {
// process the current state

View file

@ -8,6 +8,7 @@ export 'src/entity/nc_album_parser.dart';
export 'src/entity/person_parser.dart';
export 'src/entity/share_parser.dart';
export 'src/entity/sharee_parser.dart';
export 'src/entity/status_parser.dart';
export 'src/entity/tag_parser.dart';
export 'src/entity/tagged_file_parser.dart';
export 'src/type.dart';

View file

@ -27,6 +27,8 @@ class Api {
ApiPhotos photos(String userId) => ApiPhotos(this, userId);
ApiStatus status() => ApiStatus(this);
ApiSystemtags systemtags() => ApiSystemtags(this);
ApiSystemtagsRelations systemtagsRelations() => ApiSystemtagsRelations(this);

View file

@ -299,6 +299,7 @@ class Status with EquatableMixin {
const Status({
required this.version,
required this.versionString,
required this.productName,
});
@override
@ -308,10 +309,12 @@ class Status with EquatableMixin {
List<Object?> get props => [
version,
versionString,
productName,
];
final String version;
final String versionString;
final String productName;
}
@toString

View file

@ -13,6 +13,7 @@ class StatusParser {
return Status(
version: json["version"],
versionString: json["versionstring"],
productName: json["productname"],
);
}
}

View file

@ -0,0 +1,34 @@
import 'package:np_api/np_api.dart';
import 'package:test/test.dart';
void main() {
group("StatusParser", () {
group("parse", () {
test("Nextcloud 25", _nextcloud25);
});
});
}
Future<void> _nextcloud25() async {
const json = """
{
"installed": true,
"maintenance": false,
"needsDbUpgrade": false,
"version": "25.0.2.3",
"versionstring": "25.0.2",
"edition": "",
"productname": "Nextcloud",
"extendedSupport": false
}
""";
final results = await StatusParser().parse(json);
expect(
results,
const Status(
version: "25.0.2.3",
versionString: "25.0.2",
productName: "Nextcloud",
),
);
}