Skip to content

Commit

Permalink
Release V2.4.2
Browse files Browse the repository at this point in the history
  • Loading branch information
Robert-Stackflow committed Sep 8, 2024
1 parent 746f435 commit ff1ec32
Show file tree
Hide file tree
Showing 8 changed files with 137 additions and 104 deletions.
2 changes: 1 addition & 1 deletion lib/Database/database_manager.dart
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ class DatabaseManager {
_currentDbFactory = cipherDbFactory;
password = await HiveUtil.regeneratePassword();
appProvider.currentDatabasePassword = password;
ILogger.info("Database not exist and new password is $password");
ILogger.info("Database not exist and new password is generated");
await HiveUtil.setEncryptDatabaseStatus(
EncryptDatabaseStatus.defaultPassword);
}
Expand Down
153 changes: 81 additions & 72 deletions lib/Screens/home_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,7 @@ class HomeScreenState extends State<HomeScreen> with TickerProviderStateMixin {
floatingActionButton:
ResponsiveUtil.isDesktop() ? null : _buildFloatingActionButton(),
floatingActionButtonLocation: FloatingActionButtonLocation.endContained,
extendBody: true,
);
}

Expand Down Expand Up @@ -675,79 +676,87 @@ class HomeScreenState extends State<HomeScreen> with TickerProviderStateMixin {
Widget gridView = Selector<AppProvider, bool>(
selector: (context, provider) => provider.dragToReorder,
builder: (context, dragToReorder, child) => Selector<AppProvider, bool>(
selector: (context, provider) => provider.hideProgressBar,
builder: (context, hideProgressBar, child) =>
ReorderableGridView.builder(
// controller: _scrollController,
gridItemsNotifier: gridItemsNotifier,
autoScroll: true,
physics: const AlwaysScrollableScrollPhysics(),
padding:
const EdgeInsets.only(left: 10, right: 10, top: 10, bottom: 10),
gridDelegate: SliverWaterfallFlowDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: layoutType.maxCrossAxisExtent,
crossAxisSpacing: 8,
mainAxisSpacing: 8,
preferredHeight: layoutType.getHeight(hideProgressBar),
selector: (context, provider) => provider.hideBottombarWhenScrolling,
builder: (context, hideBottombarWhenScrolling, child) =>
Selector<AppProvider, bool>(
selector: (context, provider) => provider.hideProgressBar,
builder: (context, hideProgressBar, child) =>
ReorderableGridView.builder(
// controller: _scrollController,
gridItemsNotifier: gridItemsNotifier,
autoScroll: true,
physics: const AlwaysScrollableScrollPhysics(),
padding: EdgeInsets.only(
left: 10,
right: 10,
top: 10,
bottom:
hideBottombarWhenScrolling || categories.isEmpty ? 10 : 85),
gridDelegate: SliverWaterfallFlowDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: layoutType.maxCrossAxisExtent,
crossAxisSpacing: 8,
mainAxisSpacing: 8,
preferredHeight: layoutType.getHeight(hideProgressBar),
),
dragToReorder: dragToReorder,
cacheExtent: 9999,
// itemDragEnable: (index) {
// if (tokens[index].pinnedInt == 1) {
// return false;
// }
// return true;
// },
onReorderStart: (_) {
_fabScrollToHideController.hide();
_bottombarScrollToHideController.hide();
},
onReorderEnd: (_, __) {
_fabScrollToHideController.show();
_bottombarScrollToHideController.show();
},
onReorder: (int oldIndex, int newIndex) async {
final selectedToken = tokens[oldIndex];
int pinnedCount = tokens.where((e) => e.pinned).length;
if (selectedToken.pinned) {
if (newIndex >= pinnedCount) newIndex = pinnedCount - 1;
} else {
if (newIndex < pinnedCount) newIndex = pinnedCount;
}
final item = tokens.removeAt(oldIndex);
tokens.insert(newIndex, item);
for (int i = 0; i < tokens.length; i++) {
tokens[i].seq = tokens.length - i;
}
await TokenDao.updateTokens(tokens, autoBackup: false);
changeOrderType(type: OrderType.Default, doPerformSort: false);
},
proxyDecorator:
(Widget child, int index, Animation<double> animation) {
return Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
boxShadow: [
BoxShadow(
color: Theme.of(rootContext).shadowColor,
offset: const Offset(0, 4),
blurRadius: 10,
spreadRadius: 1,
).scale(2)
],
),
child: child,
);
},
itemCount: tokens.length,
itemBuilder: (context, index) {
return TokenLayout(
key: tokenKeyMap.putIfAbsent(
tokens[index].uid, () => GlobalKey()),
token: tokens[index],
layoutType: layoutType,
);
},
),
dragToReorder: dragToReorder,
cacheExtent: 9999,
// itemDragEnable: (index) {
// if (tokens[index].pinnedInt == 1) {
// return false;
// }
// return true;
// },
onReorderStart: (_) {
_fabScrollToHideController.hide();
_bottombarScrollToHideController.hide();
},
onReorderEnd: (_, __) {
_fabScrollToHideController.show();
_bottombarScrollToHideController.show();
},
onReorder: (int oldIndex, int newIndex) async {
final selectedToken = tokens[oldIndex];
int pinnedCount = tokens.where((e) => e.pinned).length;
if (selectedToken.pinned) {
if (newIndex >= pinnedCount) newIndex = pinnedCount - 1;
} else {
if (newIndex < pinnedCount) newIndex = pinnedCount;
}
final item = tokens.removeAt(oldIndex);
tokens.insert(newIndex, item);
for (int i = 0; i < tokens.length; i++) {
tokens[i].seq = tokens.length - i;
}
await TokenDao.updateTokens(tokens, autoBackup: false);
changeOrderType(type: OrderType.Default, doPerformSort: false);
},
proxyDecorator:
(Widget child, int index, Animation<double> animation) {
return Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
boxShadow: [
BoxShadow(
color: Theme.of(rootContext).shadowColor,
offset: const Offset(0, 4),
blurRadius: 10,
spreadRadius: 1,
).scale(2)
],
),
child: child,
);
},
itemCount: tokens.length,
itemBuilder: (context, index) {
return TokenLayout(
key:
tokenKeyMap.putIfAbsent(tokens[index].uid, () => GlobalKey()),
token: tokens[index],
layoutType: layoutType,
);
},
),
),
);
Expand Down
58 changes: 40 additions & 18 deletions lib/TokenUtils/export_token_util.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'dart:convert';
import 'dart:io';
import 'dart:math';

import 'package:cloudotp/Database/auto_backup_log_dao.dart';
import 'package:cloudotp/Database/category_dao.dart';
Expand Down Expand Up @@ -484,6 +485,7 @@ class ExportTokenUtil {
}
List<String> tokenQrcodes = [];
int passCount = 0;
List<OtpMigrationPayload> payloads = [];
try {
List<OtpToken> tokens = await TokenDao.listTokens();
OtpMigrationPayload payload = OtpMigrationPayload.create();
Expand All @@ -496,14 +498,22 @@ class ExportTokenUtil {
payload.otpParameters.add(token.toOtpMigrationParameters());
String currentRes = base64Encode(payload.writeToBuffer());
if (currentRes.bytesLength > maxBytesLength) {
tokenQrcodes.add(preRes);
preRes = currentRes = "";
payloads.add(payload);
payload = OtpMigrationPayload.create();
} else {
preRes = currentRes;
}
}
if (preRes.isNotEmpty) tokenQrcodes.add(preRes);
if (preRes.isNotEmpty) payloads.add(payload);
int batchId = Random().nextInt(1000000000) * -1;
for (OtpMigrationPayload payload in payloads) {
payload.batchSize = payloads.length;
payload.batchIndex = payloads.indexOf(payload);
payload.batchId = batchId;
payload.version = 1;
tokenQrcodes.add(base64Encode(payload.writeToBuffer()));
}
tokenQrcodes = tokenQrcodes
.map((e) =>
"otpauth-migration://offline?data=${Uri.encodeComponent(e)}")
Expand All @@ -526,28 +536,28 @@ class ExportTokenUtil {
if (showLoading) {
CustomLoadingDialog.showLoading(title: S.current.exporting);
}
List<String> tokenQrcodes = [];
List<String> categoryQrcodes = [];
List<String> qrcodes = [];
List<CloudOtpTokenPayload> payloads = [];
List<TokenCategoryPayload> categoryPayloads = [];
int batchId = Random().nextInt(1000000000) * -1;
try {
//Tokens
List<OtpToken> tokens = await TokenDao.listTokens();
CloudOtpTokenPayload payload = CloudOtpTokenPayload.create();
String preRes = "";
for (OtpToken token in tokens) {
payload.tokenParameters.add(token.toCloudOtpTokenParameters());
String currentRes = base64Encode(payload.writeToBuffer());
if (currentRes.bytesLength > maxBytesLength) {
tokenQrcodes.add(preRes);
payloads.add(payload);
preRes = currentRes = "";
payload = CloudOtpTokenPayload.create();
} else {
preRes = currentRes;
}
}
if (preRes.isNotEmpty) tokenQrcodes.add(preRes);
tokenQrcodes = tokenQrcodes
.map((e) =>
"cloudotpauth-migration://offline?tokens=${Uri.encodeComponent(e)}")
.toList();
if (preRes.isNotEmpty) payloads.add(payload);
//Categories
List<TokenCategory> categories = await CategoryDao.listCategories();
TokenCategoryPayload categoryPayload = TokenCategoryPayload.create();
preRes = "";
Expand All @@ -557,20 +567,32 @@ class ExportTokenUtil {
categoryPayload.categoryParameters.add(parameters);
String currentRes = base64Encode(categoryPayload.writeToBuffer());
if (currentRes.bytesLength > maxBytesLength) {
categoryQrcodes.add(preRes);
categoryPayloads.add(categoryPayload);
preRes = currentRes = "";
categoryPayload = TokenCategoryPayload.create();
} else {
preRes = currentRes;
}
}
if (preRes.isNotEmpty) categoryQrcodes.add(preRes);
categoryQrcodes = categoryQrcodes
.map((e) =>
"cloudotpauth-migration://offline?categories=${Uri.encodeComponent(e)}")
.toList();
tokenQrcodes.addAll(categoryQrcodes);
return tokenQrcodes;
if (preRes.isNotEmpty) categoryPayloads.add(categoryPayload);
for (CloudOtpTokenPayload payload in payloads) {
payload.version = 1;
payload.batchSize = payloads.length + categoryPayloads.length;
payload.batchIndex = payloads.indexOf(payload);
payload.batchId = batchId;
qrcodes.add(
"cloudotpauth-migration://offline?tokens=${Uri.encodeComponent(base64Encode(payload.writeToBuffer()))}");
}
for (TokenCategoryPayload payload in categoryPayloads) {
payload.version = 1;
payload.batchSize = payloads.length + categoryPayloads.length;
payload.batchIndex =
payloads.length + categoryPayloads.indexOf(payload);
payload.batchId = batchId;
qrcodes.add(
"cloudotpauth-migration://offline?categories=${Uri.encodeComponent(base64Encode(payload.writeToBuffer()))}");
}
return qrcodes;
} catch (e, t) {
ILogger.error("Failed to export data to qrcodes", e, t);
return null;
Expand Down
16 changes: 9 additions & 7 deletions lib/TokenUtils/otp_token_parser.dart
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,16 @@ class OtpTokenParser {
labelAndIssuer = token.account;
}
String uriText =
"otpauth://${token.tokenType.authority}/$labelAndIssuer?secret=${token.secret}&algorithm=${token.algorithm.label}&digits=${token.digits.digit}&period=${token.period}";
"otpauth://${token.tokenType.authority}/$labelAndIssuer?secret=${token
.secret}&algorithm=${token.algorithm.label}&digits=${token.digits
.digit}&period=${token.period}";
switch (token.tokenType) {
case OtpTokenType.HOTP:
uriText += "&counter=${token.counter + 1}";
break;
case OtpTokenType.MOTP:
uriText +=
"motp://$labelAndIssuer?secret=${token.secret}&pin=${token.pin}";
"motp://$labelAndIssuer?secret=${token.secret}&pin=${token.pin}";
case OtpTokenType.Yandex:
uriText += "&pin=${token.pin}";
case OtpTokenType.TOTP:
Expand Down Expand Up @@ -215,7 +217,7 @@ class OtpTokenParser {
rawData = rawData.padRight(nextFactor, '=');
}
OtpMigrationPayload payload =
OtpMigrationPayload.fromBuffer(base64Decode(rawData));
OtpMigrationPayload.fromBuffer(base64Decode(rawData));
List<OtpToken> tokens = [];
for (var param in payload.otpParameters) {
OtpToken? token = OtpToken.fromOtpMigrationParameters(param);
Expand All @@ -237,7 +239,7 @@ class OtpTokenParser {
rawData = rawData.padRight(nextFactor, '=');
}
CloudOtpTokenPayload payload =
CloudOtpTokenPayload.fromBuffer(base64Decode(rawData));
CloudOtpTokenPayload.fromBuffer(base64Decode(rawData));
List<OtpToken> tokens = [];
for (var param in payload.tokenParameters) {
OtpToken token = OtpToken.fromCloudOtpParameters(param);
Expand All @@ -259,7 +261,7 @@ class OtpTokenParser {
rawData = rawData.padRight(nextFactor, '=');
}
TokenCategoryPayload payload =
TokenCategoryPayload.fromBuffer(base64Decode(rawData));
TokenCategoryPayload.fromBuffer(base64Decode(rawData));
List<TokenCategory> categories = [];
for (var param in payload.categoryParameters) {
TokenCategory category = TokenCategory.fromCategoryParameters(param);
Expand Down Expand Up @@ -305,9 +307,9 @@ class OtpAuthMigrationData {
String username = reader.readString();
String issuer = reader.readString();
OtpAuthMigrationDataAlgorithm algorithm =
OtpAuthMigrationDataAlgorithm.values[reader.readInt32()];
OtpAuthMigrationDataAlgorithm.values[reader.readInt32()];
OtpAuthMigrationDataType type =
OtpAuthMigrationDataType.values[reader.readInt32()];
OtpAuthMigrationDataType.values[reader.readInt32()];
int counter = reader.readInt32();
return OtpAuthMigrationData(
secret: secret,
Expand Down
2 changes: 1 addition & 1 deletion lib/Utils/utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,7 @@ class Utils {
if (showLoading) {
CustomLoadingDialog.showLoading(title: S.current.checkingUpdates);
}
String currentVersion ="0.0.0"?? (await PackageInfo.fromPlatform()).version;
String currentVersion = (await PackageInfo.fromPlatform()).version;
onGetCurrentVersion?.call(currentVersion);
String latestVersion = "0.0.0";
await GithubApi.getReleases("Robert-Stackflow", "CloudOTP")
Expand Down
4 changes: 2 additions & 2 deletions pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1161,10 +1161,10 @@ packages:
dependency: "direct main"
description:
name: mobile_scanner
sha256: b8c0e9afcfd52534f85ec666f3d52156f560b5e6c25b1e3d4fe2087763607926
sha256: "82c9beb863705831a779e02e80398e61a86a48d1fcfdf4241ebd4292605acd9b"
url: "https://pub.flutter-io.cn"
source: hosted
version: "5.1.1"
version: "5.2.2"
modal_bottom_sheet:
dependency: "direct main"
description:
Expand Down
4 changes: 2 additions & 2 deletions pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: cloudotp
version: 2.4.1+241
version: 2.4.2+242
description: An awesome two-factor authenticator which supports cloud storage and multiple platforms.
publish_to: none

Expand Down Expand Up @@ -31,7 +31,7 @@ dependencies:
# 二维码
image: ^4.2.0 # 图片
zxing2: ^0.2.3 # 二维码
mobile_scanner: ^5.1.1 # 扫码
mobile_scanner: ^5.2.2 # 扫码
pretty_qr_code: ^3.3.0 # 二维码
screen_capturer:
path: third-party/screen_capturer_lib/screen_capturer
Expand Down
2 changes: 1 addition & 1 deletion tools/CloudOTP.iss
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!

#define MyAppName "CloudOTP"
#define MyAppVersion "2.4.1"
#define MyAppVersion "2.4.2"
#define MyAppPublisher "Cloudchewie"
#define MyAppURL "https://apps.cloudchewie.com/cloudotp"
#define MyAppExeName "CloudOTP.exe"
Expand Down

0 comments on commit ff1ec32

Please sign in to comment.