Skip to content

Commit ff1ec32

Browse files
Release V2.4.2
1 parent 746f435 commit ff1ec32

File tree

8 files changed

+137
-104
lines changed

8 files changed

+137
-104
lines changed

lib/Database/database_manager.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ class DatabaseManager {
7474
_currentDbFactory = cipherDbFactory;
7575
password = await HiveUtil.regeneratePassword();
7676
appProvider.currentDatabasePassword = password;
77-
ILogger.info("Database not exist and new password is $password");
77+
ILogger.info("Database not exist and new password is generated");
7878
await HiveUtil.setEncryptDatabaseStatus(
7979
EncryptDatabaseStatus.defaultPassword);
8080
}

lib/Screens/home_screen.dart

Lines changed: 81 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,7 @@ class HomeScreenState extends State<HomeScreen> with TickerProviderStateMixin {
327327
floatingActionButton:
328328
ResponsiveUtil.isDesktop() ? null : _buildFloatingActionButton(),
329329
floatingActionButtonLocation: FloatingActionButtonLocation.endContained,
330+
extendBody: true,
330331
);
331332
}
332333

@@ -675,79 +676,87 @@ class HomeScreenState extends State<HomeScreen> with TickerProviderStateMixin {
675676
Widget gridView = Selector<AppProvider, bool>(
676677
selector: (context, provider) => provider.dragToReorder,
677678
builder: (context, dragToReorder, child) => Selector<AppProvider, bool>(
678-
selector: (context, provider) => provider.hideProgressBar,
679-
builder: (context, hideProgressBar, child) =>
680-
ReorderableGridView.builder(
681-
// controller: _scrollController,
682-
gridItemsNotifier: gridItemsNotifier,
683-
autoScroll: true,
684-
physics: const AlwaysScrollableScrollPhysics(),
685-
padding:
686-
const EdgeInsets.only(left: 10, right: 10, top: 10, bottom: 10),
687-
gridDelegate: SliverWaterfallFlowDelegateWithMaxCrossAxisExtent(
688-
maxCrossAxisExtent: layoutType.maxCrossAxisExtent,
689-
crossAxisSpacing: 8,
690-
mainAxisSpacing: 8,
691-
preferredHeight: layoutType.getHeight(hideProgressBar),
679+
selector: (context, provider) => provider.hideBottombarWhenScrolling,
680+
builder: (context, hideBottombarWhenScrolling, child) =>
681+
Selector<AppProvider, bool>(
682+
selector: (context, provider) => provider.hideProgressBar,
683+
builder: (context, hideProgressBar, child) =>
684+
ReorderableGridView.builder(
685+
// controller: _scrollController,
686+
gridItemsNotifier: gridItemsNotifier,
687+
autoScroll: true,
688+
physics: const AlwaysScrollableScrollPhysics(),
689+
padding: EdgeInsets.only(
690+
left: 10,
691+
right: 10,
692+
top: 10,
693+
bottom:
694+
hideBottombarWhenScrolling || categories.isEmpty ? 10 : 85),
695+
gridDelegate: SliverWaterfallFlowDelegateWithMaxCrossAxisExtent(
696+
maxCrossAxisExtent: layoutType.maxCrossAxisExtent,
697+
crossAxisSpacing: 8,
698+
mainAxisSpacing: 8,
699+
preferredHeight: layoutType.getHeight(hideProgressBar),
700+
),
701+
dragToReorder: dragToReorder,
702+
cacheExtent: 9999,
703+
// itemDragEnable: (index) {
704+
// if (tokens[index].pinnedInt == 1) {
705+
// return false;
706+
// }
707+
// return true;
708+
// },
709+
onReorderStart: (_) {
710+
_fabScrollToHideController.hide();
711+
_bottombarScrollToHideController.hide();
712+
},
713+
onReorderEnd: (_, __) {
714+
_fabScrollToHideController.show();
715+
_bottombarScrollToHideController.show();
716+
},
717+
onReorder: (int oldIndex, int newIndex) async {
718+
final selectedToken = tokens[oldIndex];
719+
int pinnedCount = tokens.where((e) => e.pinned).length;
720+
if (selectedToken.pinned) {
721+
if (newIndex >= pinnedCount) newIndex = pinnedCount - 1;
722+
} else {
723+
if (newIndex < pinnedCount) newIndex = pinnedCount;
724+
}
725+
final item = tokens.removeAt(oldIndex);
726+
tokens.insert(newIndex, item);
727+
for (int i = 0; i < tokens.length; i++) {
728+
tokens[i].seq = tokens.length - i;
729+
}
730+
await TokenDao.updateTokens(tokens, autoBackup: false);
731+
changeOrderType(type: OrderType.Default, doPerformSort: false);
732+
},
733+
proxyDecorator:
734+
(Widget child, int index, Animation<double> animation) {
735+
return Container(
736+
decoration: BoxDecoration(
737+
borderRadius: BorderRadius.circular(12),
738+
boxShadow: [
739+
BoxShadow(
740+
color: Theme.of(rootContext).shadowColor,
741+
offset: const Offset(0, 4),
742+
blurRadius: 10,
743+
spreadRadius: 1,
744+
).scale(2)
745+
],
746+
),
747+
child: child,
748+
);
749+
},
750+
itemCount: tokens.length,
751+
itemBuilder: (context, index) {
752+
return TokenLayout(
753+
key: tokenKeyMap.putIfAbsent(
754+
tokens[index].uid, () => GlobalKey()),
755+
token: tokens[index],
756+
layoutType: layoutType,
757+
);
758+
},
692759
),
693-
dragToReorder: dragToReorder,
694-
cacheExtent: 9999,
695-
// itemDragEnable: (index) {
696-
// if (tokens[index].pinnedInt == 1) {
697-
// return false;
698-
// }
699-
// return true;
700-
// },
701-
onReorderStart: (_) {
702-
_fabScrollToHideController.hide();
703-
_bottombarScrollToHideController.hide();
704-
},
705-
onReorderEnd: (_, __) {
706-
_fabScrollToHideController.show();
707-
_bottombarScrollToHideController.show();
708-
},
709-
onReorder: (int oldIndex, int newIndex) async {
710-
final selectedToken = tokens[oldIndex];
711-
int pinnedCount = tokens.where((e) => e.pinned).length;
712-
if (selectedToken.pinned) {
713-
if (newIndex >= pinnedCount) newIndex = pinnedCount - 1;
714-
} else {
715-
if (newIndex < pinnedCount) newIndex = pinnedCount;
716-
}
717-
final item = tokens.removeAt(oldIndex);
718-
tokens.insert(newIndex, item);
719-
for (int i = 0; i < tokens.length; i++) {
720-
tokens[i].seq = tokens.length - i;
721-
}
722-
await TokenDao.updateTokens(tokens, autoBackup: false);
723-
changeOrderType(type: OrderType.Default, doPerformSort: false);
724-
},
725-
proxyDecorator:
726-
(Widget child, int index, Animation<double> animation) {
727-
return Container(
728-
decoration: BoxDecoration(
729-
borderRadius: BorderRadius.circular(12),
730-
boxShadow: [
731-
BoxShadow(
732-
color: Theme.of(rootContext).shadowColor,
733-
offset: const Offset(0, 4),
734-
blurRadius: 10,
735-
spreadRadius: 1,
736-
).scale(2)
737-
],
738-
),
739-
child: child,
740-
);
741-
},
742-
itemCount: tokens.length,
743-
itemBuilder: (context, index) {
744-
return TokenLayout(
745-
key:
746-
tokenKeyMap.putIfAbsent(tokens[index].uid, () => GlobalKey()),
747-
token: tokens[index],
748-
layoutType: layoutType,
749-
);
750-
},
751760
),
752761
),
753762
);

lib/TokenUtils/export_token_util.dart

Lines changed: 40 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import 'dart:convert';
22
import 'dart:io';
3+
import 'dart:math';
34

45
import 'package:cloudotp/Database/auto_backup_log_dao.dart';
56
import 'package:cloudotp/Database/category_dao.dart';
@@ -484,6 +485,7 @@ class ExportTokenUtil {
484485
}
485486
List<String> tokenQrcodes = [];
486487
int passCount = 0;
488+
List<OtpMigrationPayload> payloads = [];
487489
try {
488490
List<OtpToken> tokens = await TokenDao.listTokens();
489491
OtpMigrationPayload payload = OtpMigrationPayload.create();
@@ -496,14 +498,22 @@ class ExportTokenUtil {
496498
payload.otpParameters.add(token.toOtpMigrationParameters());
497499
String currentRes = base64Encode(payload.writeToBuffer());
498500
if (currentRes.bytesLength > maxBytesLength) {
499-
tokenQrcodes.add(preRes);
500501
preRes = currentRes = "";
502+
payloads.add(payload);
501503
payload = OtpMigrationPayload.create();
502504
} else {
503505
preRes = currentRes;
504506
}
505507
}
506-
if (preRes.isNotEmpty) tokenQrcodes.add(preRes);
508+
if (preRes.isNotEmpty) payloads.add(payload);
509+
int batchId = Random().nextInt(1000000000) * -1;
510+
for (OtpMigrationPayload payload in payloads) {
511+
payload.batchSize = payloads.length;
512+
payload.batchIndex = payloads.indexOf(payload);
513+
payload.batchId = batchId;
514+
payload.version = 1;
515+
tokenQrcodes.add(base64Encode(payload.writeToBuffer()));
516+
}
507517
tokenQrcodes = tokenQrcodes
508518
.map((e) =>
509519
"otpauth-migration://offline?data=${Uri.encodeComponent(e)}")
@@ -526,28 +536,28 @@ class ExportTokenUtil {
526536
if (showLoading) {
527537
CustomLoadingDialog.showLoading(title: S.current.exporting);
528538
}
529-
List<String> tokenQrcodes = [];
530-
List<String> categoryQrcodes = [];
539+
List<String> qrcodes = [];
540+
List<CloudOtpTokenPayload> payloads = [];
541+
List<TokenCategoryPayload> categoryPayloads = [];
542+
int batchId = Random().nextInt(1000000000) * -1;
531543
try {
544+
//Tokens
532545
List<OtpToken> tokens = await TokenDao.listTokens();
533546
CloudOtpTokenPayload payload = CloudOtpTokenPayload.create();
534547
String preRes = "";
535548
for (OtpToken token in tokens) {
536549
payload.tokenParameters.add(token.toCloudOtpTokenParameters());
537550
String currentRes = base64Encode(payload.writeToBuffer());
538551
if (currentRes.bytesLength > maxBytesLength) {
539-
tokenQrcodes.add(preRes);
552+
payloads.add(payload);
540553
preRes = currentRes = "";
541554
payload = CloudOtpTokenPayload.create();
542555
} else {
543556
preRes = currentRes;
544557
}
545558
}
546-
if (preRes.isNotEmpty) tokenQrcodes.add(preRes);
547-
tokenQrcodes = tokenQrcodes
548-
.map((e) =>
549-
"cloudotpauth-migration://offline?tokens=${Uri.encodeComponent(e)}")
550-
.toList();
559+
if (preRes.isNotEmpty) payloads.add(payload);
560+
//Categories
551561
List<TokenCategory> categories = await CategoryDao.listCategories();
552562
TokenCategoryPayload categoryPayload = TokenCategoryPayload.create();
553563
preRes = "";
@@ -557,20 +567,32 @@ class ExportTokenUtil {
557567
categoryPayload.categoryParameters.add(parameters);
558568
String currentRes = base64Encode(categoryPayload.writeToBuffer());
559569
if (currentRes.bytesLength > maxBytesLength) {
560-
categoryQrcodes.add(preRes);
570+
categoryPayloads.add(categoryPayload);
561571
preRes = currentRes = "";
562572
categoryPayload = TokenCategoryPayload.create();
563573
} else {
564574
preRes = currentRes;
565575
}
566576
}
567-
if (preRes.isNotEmpty) categoryQrcodes.add(preRes);
568-
categoryQrcodes = categoryQrcodes
569-
.map((e) =>
570-
"cloudotpauth-migration://offline?categories=${Uri.encodeComponent(e)}")
571-
.toList();
572-
tokenQrcodes.addAll(categoryQrcodes);
573-
return tokenQrcodes;
577+
if (preRes.isNotEmpty) categoryPayloads.add(categoryPayload);
578+
for (CloudOtpTokenPayload payload in payloads) {
579+
payload.version = 1;
580+
payload.batchSize = payloads.length + categoryPayloads.length;
581+
payload.batchIndex = payloads.indexOf(payload);
582+
payload.batchId = batchId;
583+
qrcodes.add(
584+
"cloudotpauth-migration://offline?tokens=${Uri.encodeComponent(base64Encode(payload.writeToBuffer()))}");
585+
}
586+
for (TokenCategoryPayload payload in categoryPayloads) {
587+
payload.version = 1;
588+
payload.batchSize = payloads.length + categoryPayloads.length;
589+
payload.batchIndex =
590+
payloads.length + categoryPayloads.indexOf(payload);
591+
payload.batchId = batchId;
592+
qrcodes.add(
593+
"cloudotpauth-migration://offline?categories=${Uri.encodeComponent(base64Encode(payload.writeToBuffer()))}");
594+
}
595+
return qrcodes;
574596
} catch (e, t) {
575597
ILogger.error("Failed to export data to qrcodes", e, t);
576598
return null;

lib/TokenUtils/otp_token_parser.dart

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,16 @@ class OtpTokenParser {
2323
labelAndIssuer = token.account;
2424
}
2525
String uriText =
26-
"otpauth://${token.tokenType.authority}/$labelAndIssuer?secret=${token.secret}&algorithm=${token.algorithm.label}&digits=${token.digits.digit}&period=${token.period}";
26+
"otpauth://${token.tokenType.authority}/$labelAndIssuer?secret=${token
27+
.secret}&algorithm=${token.algorithm.label}&digits=${token.digits
28+
.digit}&period=${token.period}";
2729
switch (token.tokenType) {
2830
case OtpTokenType.HOTP:
2931
uriText += "&counter=${token.counter + 1}";
3032
break;
3133
case OtpTokenType.MOTP:
3234
uriText +=
33-
"motp://$labelAndIssuer?secret=${token.secret}&pin=${token.pin}";
35+
"motp://$labelAndIssuer?secret=${token.secret}&pin=${token.pin}";
3436
case OtpTokenType.Yandex:
3537
uriText += "&pin=${token.pin}";
3638
case OtpTokenType.TOTP:
@@ -215,7 +217,7 @@ class OtpTokenParser {
215217
rawData = rawData.padRight(nextFactor, '=');
216218
}
217219
OtpMigrationPayload payload =
218-
OtpMigrationPayload.fromBuffer(base64Decode(rawData));
220+
OtpMigrationPayload.fromBuffer(base64Decode(rawData));
219221
List<OtpToken> tokens = [];
220222
for (var param in payload.otpParameters) {
221223
OtpToken? token = OtpToken.fromOtpMigrationParameters(param);
@@ -237,7 +239,7 @@ class OtpTokenParser {
237239
rawData = rawData.padRight(nextFactor, '=');
238240
}
239241
CloudOtpTokenPayload payload =
240-
CloudOtpTokenPayload.fromBuffer(base64Decode(rawData));
242+
CloudOtpTokenPayload.fromBuffer(base64Decode(rawData));
241243
List<OtpToken> tokens = [];
242244
for (var param in payload.tokenParameters) {
243245
OtpToken token = OtpToken.fromCloudOtpParameters(param);
@@ -259,7 +261,7 @@ class OtpTokenParser {
259261
rawData = rawData.padRight(nextFactor, '=');
260262
}
261263
TokenCategoryPayload payload =
262-
TokenCategoryPayload.fromBuffer(base64Decode(rawData));
264+
TokenCategoryPayload.fromBuffer(base64Decode(rawData));
263265
List<TokenCategory> categories = [];
264266
for (var param in payload.categoryParameters) {
265267
TokenCategory category = TokenCategory.fromCategoryParameters(param);
@@ -305,9 +307,9 @@ class OtpAuthMigrationData {
305307
String username = reader.readString();
306308
String issuer = reader.readString();
307309
OtpAuthMigrationDataAlgorithm algorithm =
308-
OtpAuthMigrationDataAlgorithm.values[reader.readInt32()];
310+
OtpAuthMigrationDataAlgorithm.values[reader.readInt32()];
309311
OtpAuthMigrationDataType type =
310-
OtpAuthMigrationDataType.values[reader.readInt32()];
312+
OtpAuthMigrationDataType.values[reader.readInt32()];
311313
int counter = reader.readInt32();
312314
return OtpAuthMigrationData(
313315
secret: secret,

lib/Utils/utils.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -361,7 +361,7 @@ class Utils {
361361
if (showLoading) {
362362
CustomLoadingDialog.showLoading(title: S.current.checkingUpdates);
363363
}
364-
String currentVersion ="0.0.0"?? (await PackageInfo.fromPlatform()).version;
364+
String currentVersion = (await PackageInfo.fromPlatform()).version;
365365
onGetCurrentVersion?.call(currentVersion);
366366
String latestVersion = "0.0.0";
367367
await GithubApi.getReleases("Robert-Stackflow", "CloudOTP")

pubspec.lock

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1161,10 +1161,10 @@ packages:
11611161
dependency: "direct main"
11621162
description:
11631163
name: mobile_scanner
1164-
sha256: b8c0e9afcfd52534f85ec666f3d52156f560b5e6c25b1e3d4fe2087763607926
1164+
sha256: "82c9beb863705831a779e02e80398e61a86a48d1fcfdf4241ebd4292605acd9b"
11651165
url: "https://pub.flutter-io.cn"
11661166
source: hosted
1167-
version: "5.1.1"
1167+
version: "5.2.2"
11681168
modal_bottom_sheet:
11691169
dependency: "direct main"
11701170
description:

pubspec.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name: cloudotp
2-
version: 2.4.1+241
2+
version: 2.4.2+242
33
description: An awesome two-factor authenticator which supports cloud storage and multiple platforms.
44
publish_to: none
55

@@ -31,7 +31,7 @@ dependencies:
3131
# 二维码
3232
image: ^4.2.0 # 图片
3333
zxing2: ^0.2.3 # 二维码
34-
mobile_scanner: ^5.1.1 # 扫码
34+
mobile_scanner: ^5.2.2 # 扫码
3535
pretty_qr_code: ^3.3.0 # 二维码
3636
screen_capturer:
3737
path: third-party/screen_capturer_lib/screen_capturer

tools/CloudOTP.iss

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
33

44
#define MyAppName "CloudOTP"
5-
#define MyAppVersion "2.4.1"
5+
#define MyAppVersion "2.4.2"
66
#define MyAppPublisher "Cloudchewie"
77
#define MyAppURL "https://apps.cloudchewie.com/cloudotp"
88
#define MyAppExeName "CloudOTP.exe"

0 commit comments

Comments
 (0)