ab show loading LinearProgressIndicator (#7538)

* Display the LinearProgressIndicator at the top of ab if the current ab is both empty and in a loading state.
* Add pull error like the legacy ab.
* When forcefully reading the 'ab' list, retrieve the personal ab guid to judge the current mode  to prevent server upgrades while the main window remains open

Signed-off-by: 21pages <pages21@163.com>
This commit is contained in:
21pages 2024-03-27 21:28:21 +08:00 committed by GitHub
parent cc30f7aa02
commit 22356940d9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 41 additions and 21 deletions

View File

@ -48,6 +48,10 @@ class _AddressBookState extends State<AddressBook> {
} else {
return Column(
children: [
// NOT use Offstage to wrap LinearProgressIndicator
if (gFFI.abModel.currentAbLoading.value &&
gFFI.abModel.currentAbEmpty)
const LinearProgressIndicator(),
buildErrorBanner(context,
loading: gFFI.abModel.currentAbLoading,
err: gFFI.abModel.currentAbPullError,

View File

@ -49,11 +49,11 @@ class AbModel {
RxList<String> get selectedTags => current.selectedTags;
RxBool get currentAbLoading => current.abLoading;
bool get currentAbEmpty => current.peers.isEmpty && current.tags.isEmpty;
RxString get currentAbPullError => current.pullError;
RxString get currentAbPushError => current.pushError;
String? _personalAbGuid;
RxBool legacyMode = true.obs;
var _modeTested = false; // whether the mode has been tested
final sortTags = shouldSortTags().obs;
final filterByIntersection = filterAbTagByIntersection().obs;
@ -83,7 +83,6 @@ class AbModel {
reset() async {
print("reset ab model");
_modeTested = false;
addressbooks.clear();
setCurrentName('');
await bind.mainClearAb();
@ -114,23 +113,16 @@ class AbModel {
debugPrint("pullAb, force: $force, quiet: $quiet");
if (!gFFI.userModel.isLogin) return;
if (force == null && listInitialized && current.initialized) return;
try {
if (!_modeTested) {
// Get personal address book guid
if (!listInitialized || force == ForcePullAb.listAndCurrent) {
try {
// Read personal guid every time to avoid upgrading the server without closing the main window
_personalAbGuid = null;
await _getPersonalAbGuid();
// Determine legacy mode based on whether _personalAbGuid is null
legacyMode.value = _personalAbGuid == null;
_modeTested = true;
if (!legacyMode.value) {
if (!legacyMode.value && _maxPeerOneAb == 0) {
await _getAbSettings();
}
}
} catch (e) {
debugPrint("test ab mode error: $e");
}
if (!listInitialized || force == ForcePullAb.listAndCurrent) {
try {
if (_personalAbGuid != null) {
debugPrint("pull ab list");
List<AbProfile> abProfiles = List.empty(growable: true);
@ -664,7 +656,7 @@ class AbModel {
}
}
if (!current.initialized) {
await current.pullAb(quiet: true);
await current.pullAb(quiet: false);
_saveCache();
}
_refreshTab();
@ -755,7 +747,9 @@ abstract class BaseAb {
pullError.value = "";
}
initialized = false;
initialized = await pullAbImpl(quiet: quiet);
try {
initialized = await pullAbImpl(quiet: quiet);
} catch (_) {}
abLoading.value = false;
}
@ -1257,12 +1251,12 @@ class Ab extends BaseAb {
Future<bool> pullAbImpl({quiet = false}) async {
bool ret = true;
List<Peer> tmpPeers = [];
if (!await _fetchPeers(tmpPeers)) {
if (!await _fetchPeers(tmpPeers, quiet: quiet)) {
ret = false;
}
peers.value = tmpPeers;
List<AbTag> tmpTags = [];
if (!await _fetchTags(tmpTags)) {
if (!await _fetchTags(tmpTags, quiet: quiet)) {
ret = false;
}
tags.value = tmpTags.map((e) => e.name).toList();
@ -1274,8 +1268,9 @@ class Ab extends BaseAb {
return ret;
}
Future<bool> _fetchPeers(List<Peer> tmpPeers) async {
Future<bool> _fetchPeers(List<Peer> tmpPeers, {quiet = false}) async {
final api = "${await bind.mainGetApiServer()}/api/ab/peers";
int? statusCode;
try {
var uri0 = Uri.parse(api);
final pageSize = 100;
@ -1296,6 +1291,7 @@ class Ab extends BaseAb {
var headers = getHttpHeaders();
headers['Content-Type'] = "application/json";
final resp = await http.post(uri, headers: headers);
statusCode = resp.statusCode;
Map<String, dynamic> json =
_jsonDecodeRespMap(utf8.decode(resp.bodyBytes), resp.statusCode);
if (json.containsKey('error')) {
@ -1324,13 +1320,23 @@ class Ab extends BaseAb {
} while (current * pageSize < total);
return true;
} catch (err) {
debugPrint('_fetchPeers err: ${err.toString()}');
if (!quiet) {
pullError.value =
'${translate('pull_ab_failed_tip')}: ${translate(err.toString())}';
}
} finally {
if (pullError.isNotEmpty) {
if (statusCode == 401) {
gFFI.userModel.reset(resetOther: true);
}
}
}
return false;
}
Future<bool> _fetchTags(List<AbTag> tmpTags) async {
Future<bool> _fetchTags(List<AbTag> tmpTags, {quiet = false}) async {
final api = "${await bind.mainGetApiServer()}/api/ab/tags/${profile.guid}";
int? statusCode;
try {
var uri0 = Uri.parse(api);
var uri = Uri(
@ -1342,6 +1348,7 @@ class Ab extends BaseAb {
var headers = getHttpHeaders();
headers['Content-Type'] = "application/json";
final resp = await http.post(uri, headers: headers);
statusCode = resp.statusCode;
List<dynamic> json =
_jsonDecodeRespList(utf8.decode(resp.bodyBytes), resp.statusCode);
if (resp.statusCode != 200) {
@ -1359,7 +1366,16 @@ class Ab extends BaseAb {
}
return true;
} catch (err) {
debugPrint('_fetchTags err: ${err.toString()}');
if (!quiet) {
pullError.value =
'${translate('pull_ab_failed_tip')}: ${translate(err.toString())}';
}
} finally {
if (pullError.isNotEmpty) {
if (statusCode == 401) {
gFFI.userModel.reset(resetOther: true);
}
}
}
return false;
}