mirror of
https://github.com/twonlyapp/twonly-app.git
synced 2026-10-09 02:54:14 +00:00
add joined chip to contact view
This commit is contained in:
parent
e76eead183
commit
ced68167d1
38 changed files with 1539 additions and 243 deletions
12
CHANGELOG.md
12
CHANGELOG.md
|
|
@ -1,5 +1,17 @@
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 0.6.0
|
||||||
|
|
||||||
|
- New: Stickers
|
||||||
|
- New: Home screen widgets
|
||||||
|
- New: Stories
|
||||||
|
- New: Mini games
|
||||||
|
- New: Custom avatars
|
||||||
|
- New: Arabic language (Experimental)
|
||||||
|
- Improve: Message delivery and push notification reliability
|
||||||
|
- Improve: Many smaller new changes
|
||||||
|
- Fix: Many small issues
|
||||||
|
|
||||||
## 0.5.4
|
## 0.5.4
|
||||||
|
|
||||||
- Fix: Recover broken sessions more reliably
|
- Fix: Recover broken sessions more reliably
|
||||||
|
|
|
||||||
|
|
@ -245,16 +245,21 @@ class FrbUserData {
|
||||||
final PlatformInt64 userId;
|
final PlatformInt64 userId;
|
||||||
final Uint8List username;
|
final Uint8List username;
|
||||||
final Uint8List publicIdentityKey;
|
final Uint8List publicIdentityKey;
|
||||||
|
final PlatformInt64? joinedAt;
|
||||||
|
|
||||||
const FrbUserData({
|
const FrbUserData({
|
||||||
required this.userId,
|
required this.userId,
|
||||||
required this.username,
|
required this.username,
|
||||||
required this.publicIdentityKey,
|
required this.publicIdentityKey,
|
||||||
|
this.joinedAt,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int get hashCode =>
|
int get hashCode =>
|
||||||
userId.hashCode ^ username.hashCode ^ publicIdentityKey.hashCode;
|
userId.hashCode ^
|
||||||
|
username.hashCode ^
|
||||||
|
publicIdentityKey.hashCode ^
|
||||||
|
joinedAt.hashCode;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) =>
|
bool operator ==(Object other) =>
|
||||||
|
|
@ -263,7 +268,8 @@ class FrbUserData {
|
||||||
runtimeType == other.runtimeType &&
|
runtimeType == other.runtimeType &&
|
||||||
userId == other.userId &&
|
userId == other.userId &&
|
||||||
username == other.username &&
|
username == other.username &&
|
||||||
publicIdentityKey == other.publicIdentityKey;
|
publicIdentityKey == other.publicIdentityKey &&
|
||||||
|
joinedAt == other.joinedAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Flutter-facing facade for the Rust-owned API runtime.
|
/// Flutter-facing facade for the Rust-owned API runtime.
|
||||||
|
|
@ -597,6 +603,9 @@ class RustApi {
|
||||||
static Future<void> purgeWidgetMedia() =>
|
static Future<void> purgeWidgetMedia() =>
|
||||||
RustLib.instance.api.crateBridgeApiRustApiPurgeWidgetMedia();
|
RustLib.instance.api.crateBridgeApiRustApiPurgeWidgetMedia();
|
||||||
|
|
||||||
|
static Future<void> refreshContactJoinedDates() =>
|
||||||
|
RustLib.instance.api.crateBridgeApiRustApiRefreshContactJoinedDates();
|
||||||
|
|
||||||
/// Republishes the widget manifest.
|
/// Republishes the widget manifest.
|
||||||
///
|
///
|
||||||
/// The contact groups a widget offers in its configuration UI are read from
|
/// The contact groups a widget offers in its configuration UI are read from
|
||||||
|
|
|
||||||
|
|
@ -89,7 +89,7 @@ class RustLib extends BaseEntrypoint<RustLibApi, RustLibApiImpl, RustLibWire> {
|
||||||
String get codegenVersion => '2.12.0';
|
String get codegenVersion => '2.12.0';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int get rustContentHash => -1844664049;
|
int get rustContentHash => -1901082359;
|
||||||
|
|
||||||
static const kDefaultExternalLibraryLoaderConfig =
|
static const kDefaultExternalLibraryLoaderConfig =
|
||||||
ExternalLibraryLoaderConfig(
|
ExternalLibraryLoaderConfig(
|
||||||
|
|
@ -417,6 +417,8 @@ abstract class RustLibApi extends BaseApi {
|
||||||
|
|
||||||
Future<void> crateBridgeApiRustApiPurgeWidgetMedia();
|
Future<void> crateBridgeApiRustApiPurgeWidgetMedia();
|
||||||
|
|
||||||
|
Future<void> crateBridgeApiRustApiRefreshContactJoinedDates();
|
||||||
|
|
||||||
Future<void> crateBridgeApiRustApiRefreshWidgetManifest();
|
Future<void> crateBridgeApiRustApiRefreshWidgetManifest();
|
||||||
|
|
||||||
Future<PlatformInt64> crateBridgeApiRustApiRegister({
|
Future<PlatformInt64> crateBridgeApiRustApiRegister({
|
||||||
|
|
@ -3891,7 +3893,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
);
|
);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> crateBridgeApiRustApiRefreshWidgetManifest() {
|
Future<void> crateBridgeApiRustApiRefreshContactJoinedDates() {
|
||||||
return handler.executeNormal(
|
return handler.executeNormal(
|
||||||
NormalTask(
|
NormalTask(
|
||||||
callFfi: (port_) {
|
callFfi: (port_) {
|
||||||
|
|
@ -3907,6 +3909,36 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
decodeSuccessData: sse_decode_unit,
|
decodeSuccessData: sse_decode_unit,
|
||||||
decodeErrorData: sse_decode_AnyhowException,
|
decodeErrorData: sse_decode_AnyhowException,
|
||||||
),
|
),
|
||||||
|
constMeta: kCrateBridgeApiRustApiRefreshContactJoinedDatesConstMeta,
|
||||||
|
argValues: [],
|
||||||
|
apiImpl: this,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
TaskConstMeta get kCrateBridgeApiRustApiRefreshContactJoinedDatesConstMeta =>
|
||||||
|
const TaskConstMeta(
|
||||||
|
debugName: "rust_api_refresh_contact_joined_dates",
|
||||||
|
argNames: [],
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> crateBridgeApiRustApiRefreshWidgetManifest() {
|
||||||
|
return handler.executeNormal(
|
||||||
|
NormalTask(
|
||||||
|
callFfi: (port_) {
|
||||||
|
final serializer = SseSerializer(generalizedFrbRustBinding);
|
||||||
|
pdeCallFfi(
|
||||||
|
generalizedFrbRustBinding,
|
||||||
|
serializer,
|
||||||
|
funcId: 95,
|
||||||
|
port: port_,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
codec: SseCodec(
|
||||||
|
decodeSuccessData: sse_decode_unit,
|
||||||
|
decodeErrorData: sse_decode_AnyhowException,
|
||||||
|
),
|
||||||
constMeta: kCrateBridgeApiRustApiRefreshWidgetManifestConstMeta,
|
constMeta: kCrateBridgeApiRustApiRefreshWidgetManifestConstMeta,
|
||||||
argValues: [],
|
argValues: [],
|
||||||
apiImpl: this,
|
apiImpl: this,
|
||||||
|
|
@ -3938,7 +3970,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 95,
|
funcId: 96,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -3973,7 +4005,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 96,
|
funcId: 97,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -4012,7 +4044,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 97,
|
funcId: 98,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -4054,7 +4086,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 98,
|
funcId: 99,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -4085,7 +4117,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 99,
|
funcId: 100,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -4118,7 +4150,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 100,
|
funcId: 101,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -4151,7 +4183,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 101,
|
funcId: 102,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -4186,7 +4218,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 102,
|
funcId: 103,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -4219,7 +4251,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 103,
|
funcId: 104,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -4252,7 +4284,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 104,
|
funcId: 105,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -4285,7 +4317,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 105,
|
funcId: 106,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -4322,7 +4354,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 106,
|
funcId: 107,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -4352,7 +4384,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 107,
|
funcId: 108,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -4382,7 +4414,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 108,
|
funcId: 109,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -4412,7 +4444,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 109,
|
funcId: 110,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -4445,7 +4477,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 110,
|
funcId: 111,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -4476,7 +4508,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 111,
|
funcId: 112,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -4509,7 +4541,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 112,
|
funcId: 113,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -4555,7 +4587,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 113,
|
funcId: 114,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -4611,7 +4643,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 114,
|
funcId: 115,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -4661,7 +4693,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 115,
|
funcId: 116,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -4706,7 +4738,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 116,
|
funcId: 117,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -4741,7 +4773,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 117,
|
funcId: 118,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -4776,7 +4808,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 118,
|
funcId: 119,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -4809,7 +4841,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 119,
|
funcId: 120,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -4846,7 +4878,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 120,
|
funcId: 121,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -4877,7 +4909,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 121,
|
funcId: 122,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -4915,7 +4947,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 122,
|
funcId: 123,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -4950,7 +4982,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 123,
|
funcId: 124,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -4989,7 +5021,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 124,
|
funcId: 125,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -5022,7 +5054,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 125,
|
funcId: 126,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -5053,7 +5085,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 126,
|
funcId: 127,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -5088,7 +5120,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 127,
|
funcId: 128,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -5118,7 +5150,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 128,
|
funcId: 129,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -5151,7 +5183,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 129,
|
funcId: 130,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -5186,7 +5218,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 130,
|
funcId: 131,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -5219,7 +5251,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 131,
|
funcId: 132,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -5250,7 +5282,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 132,
|
funcId: 133,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -5287,7 +5319,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 133,
|
funcId: 134,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -5339,7 +5371,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 134,
|
funcId: 135,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -5392,7 +5424,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 135,
|
funcId: 136,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -5432,7 +5464,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 136,
|
funcId: 137,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -5465,7 +5497,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 137,
|
funcId: 138,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -5498,7 +5530,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 138,
|
funcId: 139,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -5535,7 +5567,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 139,
|
funcId: 140,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -5567,7 +5599,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 140,
|
funcId: 141,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -5600,7 +5632,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 141,
|
funcId: 142,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -5635,7 +5667,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 142,
|
funcId: 143,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -5667,7 +5699,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 143,
|
funcId: 144,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -5705,7 +5737,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 144,
|
funcId: 145,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -5738,7 +5770,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 145,
|
funcId: 146,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -5776,7 +5808,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 146,
|
funcId: 147,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -5813,7 +5845,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 147,
|
funcId: 148,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -5850,7 +5882,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 148,
|
funcId: 149,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -5888,7 +5920,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 149,
|
funcId: 150,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -5926,7 +5958,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 150,
|
funcId: 151,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -5959,7 +5991,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 151,
|
funcId: 152,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -5991,7 +6023,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 152,
|
funcId: 153,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -6026,7 +6058,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 153,
|
funcId: 154,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -6063,7 +6095,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 154,
|
funcId: 155,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -6096,7 +6128,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 155,
|
funcId: 156,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -6128,7 +6160,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 156,
|
funcId: 157,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -6163,7 +6195,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 157,
|
funcId: 158,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -6202,7 +6234,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 158,
|
funcId: 159,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -6239,7 +6271,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 159,
|
funcId: 160,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -6269,7 +6301,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 160,
|
funcId: 161,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -6301,7 +6333,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 161,
|
funcId: 162,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -6336,7 +6368,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 162,
|
funcId: 163,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -6371,7 +6403,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 163,
|
funcId: 164,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -6402,7 +6434,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 164,
|
funcId: 165,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -6440,7 +6472,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 165,
|
funcId: 166,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -6475,7 +6507,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 166,
|
funcId: 167,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -6514,7 +6546,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 167,
|
funcId: 168,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -6549,7 +6581,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 168,
|
funcId: 169,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -6594,7 +6626,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 169,
|
funcId: 170,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -6637,7 +6669,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 170,
|
funcId: 171,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -6669,7 +6701,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 171,
|
funcId: 172,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -6704,7 +6736,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 172,
|
funcId: 173,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -6739,7 +6771,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 173,
|
funcId: 174,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -6774,7 +6806,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 174,
|
funcId: 175,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -6807,7 +6839,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
return pdeCallFfi(
|
return pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 175,
|
funcId: 176,
|
||||||
)!;
|
)!;
|
||||||
},
|
},
|
||||||
codec: SseCodec(
|
codec: SseCodec(
|
||||||
|
|
@ -6847,7 +6879,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 176,
|
funcId: 177,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -6892,7 +6924,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 177,
|
funcId: 178,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -6922,7 +6954,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 178,
|
funcId: 179,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -6955,7 +6987,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 179,
|
funcId: 180,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -6990,7 +7022,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
pdeCallFfi(
|
pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 180,
|
funcId: 181,
|
||||||
port: port_,
|
port: port_,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -7029,7 +7061,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
return pdeCallFfi(
|
return pdeCallFfi(
|
||||||
generalizedFrbRustBinding,
|
generalizedFrbRustBinding,
|
||||||
serializer,
|
serializer,
|
||||||
funcId: 181,
|
funcId: 182,
|
||||||
)!;
|
)!;
|
||||||
},
|
},
|
||||||
codec: SseCodec(
|
codec: SseCodec(
|
||||||
|
|
@ -7498,12 +7530,13 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
FrbUserData dco_decode_frb_user_data(dynamic raw) {
|
FrbUserData dco_decode_frb_user_data(dynamic raw) {
|
||||||
// Codec=Dco (DartCObject based), see doc to use other codecs
|
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||||
final arr = raw as List<dynamic>;
|
final arr = raw as List<dynamic>;
|
||||||
if (arr.length != 3)
|
if (arr.length != 4)
|
||||||
throw Exception('unexpected arr length: expect 3 but see ${arr.length}');
|
throw Exception('unexpected arr length: expect 4 but see ${arr.length}');
|
||||||
return FrbUserData(
|
return FrbUserData(
|
||||||
userId: dco_decode_i_64(arr[0]),
|
userId: dco_decode_i_64(arr[0]),
|
||||||
username: dco_decode_list_prim_u_8_strict(arr[1]),
|
username: dco_decode_list_prim_u_8_strict(arr[1]),
|
||||||
publicIdentityKey: dco_decode_list_prim_u_8_strict(arr[2]),
|
publicIdentityKey: dco_decode_list_prim_u_8_strict(arr[2]),
|
||||||
|
joinedAt: dco_decode_opt_box_autoadd_i_64(arr[3]),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -8128,8 +8161,8 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
UserConfig dco_decode_user_config(dynamic raw) {
|
UserConfig dco_decode_user_config(dynamic raw) {
|
||||||
// Codec=Dco (DartCObject based), see doc to use other codecs
|
// Codec=Dco (DartCObject based), see doc to use other codecs
|
||||||
final arr = raw as List<dynamic>;
|
final arr = raw as List<dynamic>;
|
||||||
if (arr.length != 65)
|
if (arr.length != 66)
|
||||||
throw Exception('unexpected arr length: expect 65 but see ${arr.length}');
|
throw Exception('unexpected arr length: expect 66 but see ${arr.length}');
|
||||||
return UserConfig(
|
return UserConfig(
|
||||||
userId: dco_decode_i_64(arr[0]),
|
userId: dco_decode_i_64(arr[0]),
|
||||||
username: dco_decode_String(arr[1]),
|
username: dco_decode_String(arr[1]),
|
||||||
|
|
@ -8187,20 +8220,21 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
currentSignedPreKeyIndexStart: dco_decode_i_64(arr[49]),
|
currentSignedPreKeyIndexStart: dco_decode_i_64(arr[49]),
|
||||||
lastChangeLogHash: dco_decode_opt_list_prim_u_8_strict(arr[50]),
|
lastChangeLogHash: dco_decode_opt_list_prim_u_8_strict(arr[50]),
|
||||||
hideChangeLog: dco_decode_bool(arr[51]),
|
hideChangeLog: dco_decode_bool(arr[51]),
|
||||||
hideMemoriesBackupPromo: dco_decode_bool(arr[52]),
|
lastReleaseNotesVersion: dco_decode_opt_String(arr[52]),
|
||||||
hideWidgetShareExplainer: dco_decode_bool(arr[53]),
|
hideMemoriesBackupPromo: dco_decode_bool(arr[53]),
|
||||||
updateFcmToken: dco_decode_bool(arr[54]),
|
hideWidgetShareExplainer: dco_decode_bool(arr[54]),
|
||||||
canUseLoginTokenForAuth: dco_decode_bool(arr[55]),
|
updateFcmToken: dco_decode_bool(arr[55]),
|
||||||
twonlySafeBackup: dco_decode_opt_box_autoadd_twonly_safe_backup(arr[56]),
|
canUseLoginTokenForAuth: dco_decode_bool(arr[56]),
|
||||||
isBackupEnabled: dco_decode_bool(arr[57]),
|
twonlySafeBackup: dco_decode_opt_box_autoadd_twonly_safe_backup(arr[57]),
|
||||||
|
isBackupEnabled: dco_decode_bool(arr[58]),
|
||||||
passwordLessRecovery:
|
passwordLessRecovery:
|
||||||
dco_decode_opt_box_autoadd_passwordless_recovery_config(arr[58]),
|
dco_decode_opt_box_autoadd_passwordless_recovery_config(arr[59]),
|
||||||
fcmToken: dco_decode_opt_String(arr[59]),
|
fcmToken: dco_decode_opt_String(arr[60]),
|
||||||
lastFcmWakeupAt: dco_decode_opt_box_autoadd_i_64(arr[60]),
|
lastFcmWakeupAt: dco_decode_opt_box_autoadd_i_64(arr[61]),
|
||||||
lastServerMessageAt: dco_decode_opt_box_autoadd_i_64(arr[61]),
|
lastServerMessageAt: dco_decode_opt_box_autoadd_i_64(arr[62]),
|
||||||
currentSetupPage: dco_decode_opt_String(arr[62]),
|
currentSetupPage: dco_decode_opt_String(arr[63]),
|
||||||
skipSetupPages: dco_decode_bool(arr[63]),
|
skipSetupPages: dco_decode_bool(arr[64]),
|
||||||
hasZoomed: dco_decode_bool(arr[64]),
|
hasZoomed: dco_decode_bool(arr[65]),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -8709,10 +8743,12 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
var var_userId = sse_decode_i_64(deserializer);
|
var var_userId = sse_decode_i_64(deserializer);
|
||||||
var var_username = sse_decode_list_prim_u_8_strict(deserializer);
|
var var_username = sse_decode_list_prim_u_8_strict(deserializer);
|
||||||
var var_publicIdentityKey = sse_decode_list_prim_u_8_strict(deserializer);
|
var var_publicIdentityKey = sse_decode_list_prim_u_8_strict(deserializer);
|
||||||
|
var var_joinedAt = sse_decode_opt_box_autoadd_i_64(deserializer);
|
||||||
return FrbUserData(
|
return FrbUserData(
|
||||||
userId: var_userId,
|
userId: var_userId,
|
||||||
username: var_username,
|
username: var_username,
|
||||||
publicIdentityKey: var_publicIdentityKey,
|
publicIdentityKey: var_publicIdentityKey,
|
||||||
|
joinedAt: var_joinedAt,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -9566,6 +9602,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
deserializer,
|
deserializer,
|
||||||
);
|
);
|
||||||
var var_hideChangeLog = sse_decode_bool(deserializer);
|
var var_hideChangeLog = sse_decode_bool(deserializer);
|
||||||
|
var var_lastReleaseNotesVersion = sse_decode_opt_String(deserializer);
|
||||||
var var_hideMemoriesBackupPromo = sse_decode_bool(deserializer);
|
var var_hideMemoriesBackupPromo = sse_decode_bool(deserializer);
|
||||||
var var_hideWidgetShareExplainer = sse_decode_bool(deserializer);
|
var var_hideWidgetShareExplainer = sse_decode_bool(deserializer);
|
||||||
var var_updateFcmToken = sse_decode_bool(deserializer);
|
var var_updateFcmToken = sse_decode_bool(deserializer);
|
||||||
|
|
@ -9638,6 +9675,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
currentSignedPreKeyIndexStart: var_currentSignedPreKeyIndexStart,
|
currentSignedPreKeyIndexStart: var_currentSignedPreKeyIndexStart,
|
||||||
lastChangeLogHash: var_lastChangeLogHash,
|
lastChangeLogHash: var_lastChangeLogHash,
|
||||||
hideChangeLog: var_hideChangeLog,
|
hideChangeLog: var_hideChangeLog,
|
||||||
|
lastReleaseNotesVersion: var_lastReleaseNotesVersion,
|
||||||
hideMemoriesBackupPromo: var_hideMemoriesBackupPromo,
|
hideMemoriesBackupPromo: var_hideMemoriesBackupPromo,
|
||||||
hideWidgetShareExplainer: var_hideWidgetShareExplainer,
|
hideWidgetShareExplainer: var_hideWidgetShareExplainer,
|
||||||
updateFcmToken: var_updateFcmToken,
|
updateFcmToken: var_updateFcmToken,
|
||||||
|
|
@ -10209,6 +10247,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
sse_encode_i_64(self.userId, serializer);
|
sse_encode_i_64(self.userId, serializer);
|
||||||
sse_encode_list_prim_u_8_strict(self.username, serializer);
|
sse_encode_list_prim_u_8_strict(self.username, serializer);
|
||||||
sse_encode_list_prim_u_8_strict(self.publicIdentityKey, serializer);
|
sse_encode_list_prim_u_8_strict(self.publicIdentityKey, serializer);
|
||||||
|
sse_encode_opt_box_autoadd_i_64(self.joinedAt, serializer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
|
|
@ -10984,6 +11023,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
|
||||||
sse_encode_i_64(self.currentSignedPreKeyIndexStart, serializer);
|
sse_encode_i_64(self.currentSignedPreKeyIndexStart, serializer);
|
||||||
sse_encode_opt_list_prim_u_8_strict(self.lastChangeLogHash, serializer);
|
sse_encode_opt_list_prim_u_8_strict(self.lastChangeLogHash, serializer);
|
||||||
sse_encode_bool(self.hideChangeLog, serializer);
|
sse_encode_bool(self.hideChangeLog, serializer);
|
||||||
|
sse_encode_opt_String(self.lastReleaseNotesVersion, serializer);
|
||||||
sse_encode_bool(self.hideMemoriesBackupPromo, serializer);
|
sse_encode_bool(self.hideMemoriesBackupPromo, serializer);
|
||||||
sse_encode_bool(self.hideWidgetShareExplainer, serializer);
|
sse_encode_bool(self.hideWidgetShareExplainer, serializer);
|
||||||
sse_encode_bool(self.updateFcmToken, serializer);
|
sse_encode_bool(self.updateFcmToken, serializer);
|
||||||
|
|
|
||||||
|
|
@ -175,6 +175,9 @@ class UserConfig {
|
||||||
PlatformInt64 currentSignedPreKeyIndexStart;
|
PlatformInt64 currentSignedPreKeyIndexStart;
|
||||||
Uint8List? lastChangeLogHash;
|
Uint8List? lastChangeLogHash;
|
||||||
bool hideChangeLog;
|
bool hideChangeLog;
|
||||||
|
|
||||||
|
/// Last in-app release note the user dismissed.
|
||||||
|
String? lastReleaseNotesVersion;
|
||||||
bool hideMemoriesBackupPromo;
|
bool hideMemoriesBackupPromo;
|
||||||
bool hideWidgetShareExplainer;
|
bool hideWidgetShareExplainer;
|
||||||
bool updateFcmToken;
|
bool updateFcmToken;
|
||||||
|
|
@ -250,6 +253,7 @@ class UserConfig {
|
||||||
required this.currentSignedPreKeyIndexStart,
|
required this.currentSignedPreKeyIndexStart,
|
||||||
this.lastChangeLogHash,
|
this.lastChangeLogHash,
|
||||||
required this.hideChangeLog,
|
required this.hideChangeLog,
|
||||||
|
this.lastReleaseNotesVersion,
|
||||||
required this.hideMemoriesBackupPromo,
|
required this.hideMemoriesBackupPromo,
|
||||||
required this.hideWidgetShareExplainer,
|
required this.hideWidgetShareExplainer,
|
||||||
required this.updateFcmToken,
|
required this.updateFcmToken,
|
||||||
|
|
@ -319,6 +323,7 @@ class UserConfig {
|
||||||
currentSignedPreKeyIndexStart.hashCode ^
|
currentSignedPreKeyIndexStart.hashCode ^
|
||||||
lastChangeLogHash.hashCode ^
|
lastChangeLogHash.hashCode ^
|
||||||
hideChangeLog.hashCode ^
|
hideChangeLog.hashCode ^
|
||||||
|
lastReleaseNotesVersion.hashCode ^
|
||||||
hideMemoriesBackupPromo.hashCode ^
|
hideMemoriesBackupPromo.hashCode ^
|
||||||
hideWidgetShareExplainer.hashCode ^
|
hideWidgetShareExplainer.hashCode ^
|
||||||
updateFcmToken.hashCode ^
|
updateFcmToken.hashCode ^
|
||||||
|
|
@ -397,6 +402,7 @@ class UserConfig {
|
||||||
other.currentSignedPreKeyIndexStart &&
|
other.currentSignedPreKeyIndexStart &&
|
||||||
lastChangeLogHash == other.lastChangeLogHash &&
|
lastChangeLogHash == other.lastChangeLogHash &&
|
||||||
hideChangeLog == other.hideChangeLog &&
|
hideChangeLog == other.hideChangeLog &&
|
||||||
|
lastReleaseNotesVersion == other.lastReleaseNotesVersion &&
|
||||||
hideMemoriesBackupPromo == other.hideMemoriesBackupPromo &&
|
hideMemoriesBackupPromo == other.hideMemoriesBackupPromo &&
|
||||||
hideWidgetShareExplainer == other.hideWidgetShareExplainer &&
|
hideWidgetShareExplainer == other.hideWidgetShareExplainer &&
|
||||||
updateFcmToken == other.updateFcmToken &&
|
updateFcmToken == other.updateFcmToken &&
|
||||||
|
|
|
||||||
|
|
@ -310,6 +310,10 @@ Future<void> postStartupTasks() async {
|
||||||
RustApi.finishStartedMediaUploads(),
|
RustApi.finishStartedMediaUploads(),
|
||||||
'finishStartedMediaUploads',
|
'finishStartedMediaUploads',
|
||||||
);
|
);
|
||||||
|
unawaitedRustCall(
|
||||||
|
RustApi.refreshContactJoinedDates(),
|
||||||
|
'refreshContactJoinedDates',
|
||||||
|
);
|
||||||
unawaited(
|
unawaited(
|
||||||
newsService.init().then((_) {
|
newsService.init().then((_) {
|
||||||
final lastDownload = newsService.lastDownloadedAt;
|
final lastDownload = newsService.lastDownloadedAt;
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,7 @@ class Contacts extends Table {
|
||||||
boolean().withDefault(const Constant(false))();
|
boolean().withDefault(const Constant(false))();
|
||||||
|
|
||||||
IntColumn get twonlyScore => integer().nullable()();
|
IntColumn get twonlyScore => integer().nullable()();
|
||||||
|
DateTimeColumn get joinedAt => dateTime().nullable()();
|
||||||
|
|
||||||
IntColumn get mediaSendCounter => integer().withDefault(const Constant(0))();
|
IntColumn get mediaSendCounter => integer().withDefault(const Constant(0))();
|
||||||
IntColumn get mediaReceivedCounter =>
|
IntColumn get mediaReceivedCounter =>
|
||||||
|
|
|
||||||
|
|
@ -348,6 +348,17 @@ class $ContactsTable extends Contacts with TableInfo<$ContactsTable, Contact> {
|
||||||
type: DriftSqlType.int,
|
type: DriftSqlType.int,
|
||||||
requiredDuringInsert: false,
|
requiredDuringInsert: false,
|
||||||
);
|
);
|
||||||
|
static const VerificationMeta _joinedAtMeta = const VerificationMeta(
|
||||||
|
'joinedAt',
|
||||||
|
);
|
||||||
|
@override
|
||||||
|
late final GeneratedColumn<DateTime> joinedAt = GeneratedColumn<DateTime>(
|
||||||
|
'joined_at',
|
||||||
|
aliasedName,
|
||||||
|
true,
|
||||||
|
type: DriftSqlType.dateTime,
|
||||||
|
requiredDuringInsert: false,
|
||||||
|
);
|
||||||
static const VerificationMeta _mediaSendCounterMeta = const VerificationMeta(
|
static const VerificationMeta _mediaSendCounterMeta = const VerificationMeta(
|
||||||
'mediaSendCounter',
|
'mediaSendCounter',
|
||||||
);
|
);
|
||||||
|
|
@ -400,6 +411,7 @@ class $ContactsTable extends Contacts with TableInfo<$ContactsTable, Contact> {
|
||||||
widgetSharingAllowed,
|
widgetSharingAllowed,
|
||||||
widgetSharingGranted,
|
widgetSharingGranted,
|
||||||
twonlyScore,
|
twonlyScore,
|
||||||
|
joinedAt,
|
||||||
mediaSendCounter,
|
mediaSendCounter,
|
||||||
mediaReceivedCounter,
|
mediaReceivedCounter,
|
||||||
];
|
];
|
||||||
|
|
@ -627,6 +639,12 @@ class $ContactsTable extends Contacts with TableInfo<$ContactsTable, Contact> {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
if (data.containsKey('joined_at')) {
|
||||||
|
context.handle(
|
||||||
|
_joinedAtMeta,
|
||||||
|
joinedAt.isAcceptableOrUnknown(data['joined_at']!, _joinedAtMeta),
|
||||||
|
);
|
||||||
|
}
|
||||||
if (data.containsKey('media_send_counter')) {
|
if (data.containsKey('media_send_counter')) {
|
||||||
context.handle(
|
context.handle(
|
||||||
_mediaSendCounterMeta,
|
_mediaSendCounterMeta,
|
||||||
|
|
@ -764,6 +782,10 @@ class $ContactsTable extends Contacts with TableInfo<$ContactsTable, Contact> {
|
||||||
DriftSqlType.int,
|
DriftSqlType.int,
|
||||||
data['${effectivePrefix}twonly_score'],
|
data['${effectivePrefix}twonly_score'],
|
||||||
),
|
),
|
||||||
|
joinedAt: attachedDatabase.typeMapping.read(
|
||||||
|
DriftSqlType.dateTime,
|
||||||
|
data['${effectivePrefix}joined_at'],
|
||||||
|
),
|
||||||
mediaSendCounter: attachedDatabase.typeMapping.read(
|
mediaSendCounter: attachedDatabase.typeMapping.read(
|
||||||
DriftSqlType.int,
|
DriftSqlType.int,
|
||||||
data['${effectivePrefix}media_send_counter'],
|
data['${effectivePrefix}media_send_counter'],
|
||||||
|
|
@ -814,6 +836,7 @@ class Contact extends DataClass implements Insertable<Contact> {
|
||||||
final bool widgetSharingAllowed;
|
final bool widgetSharingAllowed;
|
||||||
final bool widgetSharingGranted;
|
final bool widgetSharingGranted;
|
||||||
final int? twonlyScore;
|
final int? twonlyScore;
|
||||||
|
final DateTime? joinedAt;
|
||||||
final int mediaSendCounter;
|
final int mediaSendCounter;
|
||||||
final int mediaReceivedCounter;
|
final int mediaReceivedCounter;
|
||||||
const Contact({
|
const Contact({
|
||||||
|
|
@ -844,6 +867,7 @@ class Contact extends DataClass implements Insertable<Contact> {
|
||||||
required this.widgetSharingAllowed,
|
required this.widgetSharingAllowed,
|
||||||
required this.widgetSharingGranted,
|
required this.widgetSharingGranted,
|
||||||
this.twonlyScore,
|
this.twonlyScore,
|
||||||
|
this.joinedAt,
|
||||||
required this.mediaSendCounter,
|
required this.mediaSendCounter,
|
||||||
required this.mediaReceivedCounter,
|
required this.mediaReceivedCounter,
|
||||||
});
|
});
|
||||||
|
|
@ -915,6 +939,9 @@ class Contact extends DataClass implements Insertable<Contact> {
|
||||||
if (!nullToAbsent || twonlyScore != null) {
|
if (!nullToAbsent || twonlyScore != null) {
|
||||||
map['twonly_score'] = Variable<int>(twonlyScore);
|
map['twonly_score'] = Variable<int>(twonlyScore);
|
||||||
}
|
}
|
||||||
|
if (!nullToAbsent || joinedAt != null) {
|
||||||
|
map['joined_at'] = Variable<DateTime>(joinedAt);
|
||||||
|
}
|
||||||
map['media_send_counter'] = Variable<int>(mediaSendCounter);
|
map['media_send_counter'] = Variable<int>(mediaSendCounter);
|
||||||
map['media_received_counter'] = Variable<int>(mediaReceivedCounter);
|
map['media_received_counter'] = Variable<int>(mediaReceivedCounter);
|
||||||
return map;
|
return map;
|
||||||
|
|
@ -977,6 +1004,9 @@ class Contact extends DataClass implements Insertable<Contact> {
|
||||||
twonlyScore: twonlyScore == null && nullToAbsent
|
twonlyScore: twonlyScore == null && nullToAbsent
|
||||||
? const Value.absent()
|
? const Value.absent()
|
||||||
: Value(twonlyScore),
|
: Value(twonlyScore),
|
||||||
|
joinedAt: joinedAt == null && nullToAbsent
|
||||||
|
? const Value.absent()
|
||||||
|
: Value(joinedAt),
|
||||||
mediaSendCounter: Value(mediaSendCounter),
|
mediaSendCounter: Value(mediaSendCounter),
|
||||||
mediaReceivedCounter: Value(mediaReceivedCounter),
|
mediaReceivedCounter: Value(mediaReceivedCounter),
|
||||||
);
|
);
|
||||||
|
|
@ -1045,6 +1075,7 @@ class Contact extends DataClass implements Insertable<Contact> {
|
||||||
json['widgetSharingGranted'],
|
json['widgetSharingGranted'],
|
||||||
),
|
),
|
||||||
twonlyScore: serializer.fromJson<int?>(json['twonlyScore']),
|
twonlyScore: serializer.fromJson<int?>(json['twonlyScore']),
|
||||||
|
joinedAt: serializer.fromJson<DateTime?>(json['joinedAt']),
|
||||||
mediaSendCounter: serializer.fromJson<int>(json['mediaSendCounter']),
|
mediaSendCounter: serializer.fromJson<int>(json['mediaSendCounter']),
|
||||||
mediaReceivedCounter: serializer.fromJson<int>(
|
mediaReceivedCounter: serializer.fromJson<int>(
|
||||||
json['mediaReceivedCounter'],
|
json['mediaReceivedCounter'],
|
||||||
|
|
@ -1100,6 +1131,7 @@ class Contact extends DataClass implements Insertable<Contact> {
|
||||||
'widgetSharingAllowed': serializer.toJson<bool>(widgetSharingAllowed),
|
'widgetSharingAllowed': serializer.toJson<bool>(widgetSharingAllowed),
|
||||||
'widgetSharingGranted': serializer.toJson<bool>(widgetSharingGranted),
|
'widgetSharingGranted': serializer.toJson<bool>(widgetSharingGranted),
|
||||||
'twonlyScore': serializer.toJson<int?>(twonlyScore),
|
'twonlyScore': serializer.toJson<int?>(twonlyScore),
|
||||||
|
'joinedAt': serializer.toJson<DateTime?>(joinedAt),
|
||||||
'mediaSendCounter': serializer.toJson<int>(mediaSendCounter),
|
'mediaSendCounter': serializer.toJson<int>(mediaSendCounter),
|
||||||
'mediaReceivedCounter': serializer.toJson<int>(mediaReceivedCounter),
|
'mediaReceivedCounter': serializer.toJson<int>(mediaReceivedCounter),
|
||||||
};
|
};
|
||||||
|
|
@ -1133,6 +1165,7 @@ class Contact extends DataClass implements Insertable<Contact> {
|
||||||
bool? widgetSharingAllowed,
|
bool? widgetSharingAllowed,
|
||||||
bool? widgetSharingGranted,
|
bool? widgetSharingGranted,
|
||||||
Value<int?> twonlyScore = const Value.absent(),
|
Value<int?> twonlyScore = const Value.absent(),
|
||||||
|
Value<DateTime?> joinedAt = const Value.absent(),
|
||||||
int? mediaSendCounter,
|
int? mediaSendCounter,
|
||||||
int? mediaReceivedCounter,
|
int? mediaReceivedCounter,
|
||||||
}) => Contact(
|
}) => Contact(
|
||||||
|
|
@ -1182,6 +1215,7 @@ class Contact extends DataClass implements Insertable<Contact> {
|
||||||
widgetSharingAllowed: widgetSharingAllowed ?? this.widgetSharingAllowed,
|
widgetSharingAllowed: widgetSharingAllowed ?? this.widgetSharingAllowed,
|
||||||
widgetSharingGranted: widgetSharingGranted ?? this.widgetSharingGranted,
|
widgetSharingGranted: widgetSharingGranted ?? this.widgetSharingGranted,
|
||||||
twonlyScore: twonlyScore.present ? twonlyScore.value : this.twonlyScore,
|
twonlyScore: twonlyScore.present ? twonlyScore.value : this.twonlyScore,
|
||||||
|
joinedAt: joinedAt.present ? joinedAt.value : this.joinedAt,
|
||||||
mediaSendCounter: mediaSendCounter ?? this.mediaSendCounter,
|
mediaSendCounter: mediaSendCounter ?? this.mediaSendCounter,
|
||||||
mediaReceivedCounter: mediaReceivedCounter ?? this.mediaReceivedCounter,
|
mediaReceivedCounter: mediaReceivedCounter ?? this.mediaReceivedCounter,
|
||||||
);
|
);
|
||||||
|
|
@ -1252,6 +1286,7 @@ class Contact extends DataClass implements Insertable<Contact> {
|
||||||
twonlyScore: data.twonlyScore.present
|
twonlyScore: data.twonlyScore.present
|
||||||
? data.twonlyScore.value
|
? data.twonlyScore.value
|
||||||
: this.twonlyScore,
|
: this.twonlyScore,
|
||||||
|
joinedAt: data.joinedAt.present ? data.joinedAt.value : this.joinedAt,
|
||||||
mediaSendCounter: data.mediaSendCounter.present
|
mediaSendCounter: data.mediaSendCounter.present
|
||||||
? data.mediaSendCounter.value
|
? data.mediaSendCounter.value
|
||||||
: this.mediaSendCounter,
|
: this.mediaSendCounter,
|
||||||
|
|
@ -1293,6 +1328,7 @@ class Contact extends DataClass implements Insertable<Contact> {
|
||||||
..write('widgetSharingAllowed: $widgetSharingAllowed, ')
|
..write('widgetSharingAllowed: $widgetSharingAllowed, ')
|
||||||
..write('widgetSharingGranted: $widgetSharingGranted, ')
|
..write('widgetSharingGranted: $widgetSharingGranted, ')
|
||||||
..write('twonlyScore: $twonlyScore, ')
|
..write('twonlyScore: $twonlyScore, ')
|
||||||
|
..write('joinedAt: $joinedAt, ')
|
||||||
..write('mediaSendCounter: $mediaSendCounter, ')
|
..write('mediaSendCounter: $mediaSendCounter, ')
|
||||||
..write('mediaReceivedCounter: $mediaReceivedCounter')
|
..write('mediaReceivedCounter: $mediaReceivedCounter')
|
||||||
..write(')'))
|
..write(')'))
|
||||||
|
|
@ -1328,6 +1364,7 @@ class Contact extends DataClass implements Insertable<Contact> {
|
||||||
widgetSharingAllowed,
|
widgetSharingAllowed,
|
||||||
widgetSharingGranted,
|
widgetSharingGranted,
|
||||||
twonlyScore,
|
twonlyScore,
|
||||||
|
joinedAt,
|
||||||
mediaSendCounter,
|
mediaSendCounter,
|
||||||
mediaReceivedCounter,
|
mediaReceivedCounter,
|
||||||
]);
|
]);
|
||||||
|
|
@ -1376,6 +1413,7 @@ class Contact extends DataClass implements Insertable<Contact> {
|
||||||
other.widgetSharingAllowed == this.widgetSharingAllowed &&
|
other.widgetSharingAllowed == this.widgetSharingAllowed &&
|
||||||
other.widgetSharingGranted == this.widgetSharingGranted &&
|
other.widgetSharingGranted == this.widgetSharingGranted &&
|
||||||
other.twonlyScore == this.twonlyScore &&
|
other.twonlyScore == this.twonlyScore &&
|
||||||
|
other.joinedAt == this.joinedAt &&
|
||||||
other.mediaSendCounter == this.mediaSendCounter &&
|
other.mediaSendCounter == this.mediaSendCounter &&
|
||||||
other.mediaReceivedCounter == this.mediaReceivedCounter);
|
other.mediaReceivedCounter == this.mediaReceivedCounter);
|
||||||
}
|
}
|
||||||
|
|
@ -1408,6 +1446,7 @@ class ContactsCompanion extends UpdateCompanion<Contact> {
|
||||||
final Value<bool> widgetSharingAllowed;
|
final Value<bool> widgetSharingAllowed;
|
||||||
final Value<bool> widgetSharingGranted;
|
final Value<bool> widgetSharingGranted;
|
||||||
final Value<int?> twonlyScore;
|
final Value<int?> twonlyScore;
|
||||||
|
final Value<DateTime?> joinedAt;
|
||||||
final Value<int> mediaSendCounter;
|
final Value<int> mediaSendCounter;
|
||||||
final Value<int> mediaReceivedCounter;
|
final Value<int> mediaReceivedCounter;
|
||||||
const ContactsCompanion({
|
const ContactsCompanion({
|
||||||
|
|
@ -1438,6 +1477,7 @@ class ContactsCompanion extends UpdateCompanion<Contact> {
|
||||||
this.widgetSharingAllowed = const Value.absent(),
|
this.widgetSharingAllowed = const Value.absent(),
|
||||||
this.widgetSharingGranted = const Value.absent(),
|
this.widgetSharingGranted = const Value.absent(),
|
||||||
this.twonlyScore = const Value.absent(),
|
this.twonlyScore = const Value.absent(),
|
||||||
|
this.joinedAt = const Value.absent(),
|
||||||
this.mediaSendCounter = const Value.absent(),
|
this.mediaSendCounter = const Value.absent(),
|
||||||
this.mediaReceivedCounter = const Value.absent(),
|
this.mediaReceivedCounter = const Value.absent(),
|
||||||
});
|
});
|
||||||
|
|
@ -1469,6 +1509,7 @@ class ContactsCompanion extends UpdateCompanion<Contact> {
|
||||||
this.widgetSharingAllowed = const Value.absent(),
|
this.widgetSharingAllowed = const Value.absent(),
|
||||||
this.widgetSharingGranted = const Value.absent(),
|
this.widgetSharingGranted = const Value.absent(),
|
||||||
this.twonlyScore = const Value.absent(),
|
this.twonlyScore = const Value.absent(),
|
||||||
|
this.joinedAt = const Value.absent(),
|
||||||
this.mediaSendCounter = const Value.absent(),
|
this.mediaSendCounter = const Value.absent(),
|
||||||
this.mediaReceivedCounter = const Value.absent(),
|
this.mediaReceivedCounter = const Value.absent(),
|
||||||
}) : username = Value(username);
|
}) : username = Value(username);
|
||||||
|
|
@ -1500,6 +1541,7 @@ class ContactsCompanion extends UpdateCompanion<Contact> {
|
||||||
Expression<bool>? widgetSharingAllowed,
|
Expression<bool>? widgetSharingAllowed,
|
||||||
Expression<bool>? widgetSharingGranted,
|
Expression<bool>? widgetSharingGranted,
|
||||||
Expression<int>? twonlyScore,
|
Expression<int>? twonlyScore,
|
||||||
|
Expression<DateTime>? joinedAt,
|
||||||
Expression<int>? mediaSendCounter,
|
Expression<int>? mediaSendCounter,
|
||||||
Expression<int>? mediaReceivedCounter,
|
Expression<int>? mediaReceivedCounter,
|
||||||
}) {
|
}) {
|
||||||
|
|
@ -1545,6 +1587,7 @@ class ContactsCompanion extends UpdateCompanion<Contact> {
|
||||||
if (widgetSharingGranted != null)
|
if (widgetSharingGranted != null)
|
||||||
'widget_sharing_granted': widgetSharingGranted,
|
'widget_sharing_granted': widgetSharingGranted,
|
||||||
if (twonlyScore != null) 'twonly_score': twonlyScore,
|
if (twonlyScore != null) 'twonly_score': twonlyScore,
|
||||||
|
if (joinedAt != null) 'joined_at': joinedAt,
|
||||||
if (mediaSendCounter != null) 'media_send_counter': mediaSendCounter,
|
if (mediaSendCounter != null) 'media_send_counter': mediaSendCounter,
|
||||||
if (mediaReceivedCounter != null)
|
if (mediaReceivedCounter != null)
|
||||||
'media_received_counter': mediaReceivedCounter,
|
'media_received_counter': mediaReceivedCounter,
|
||||||
|
|
@ -1579,6 +1622,7 @@ class ContactsCompanion extends UpdateCompanion<Contact> {
|
||||||
Value<bool>? widgetSharingAllowed,
|
Value<bool>? widgetSharingAllowed,
|
||||||
Value<bool>? widgetSharingGranted,
|
Value<bool>? widgetSharingGranted,
|
||||||
Value<int?>? twonlyScore,
|
Value<int?>? twonlyScore,
|
||||||
|
Value<DateTime?>? joinedAt,
|
||||||
Value<int>? mediaSendCounter,
|
Value<int>? mediaSendCounter,
|
||||||
Value<int>? mediaReceivedCounter,
|
Value<int>? mediaReceivedCounter,
|
||||||
}) {
|
}) {
|
||||||
|
|
@ -1618,6 +1662,7 @@ class ContactsCompanion extends UpdateCompanion<Contact> {
|
||||||
widgetSharingAllowed: widgetSharingAllowed ?? this.widgetSharingAllowed,
|
widgetSharingAllowed: widgetSharingAllowed ?? this.widgetSharingAllowed,
|
||||||
widgetSharingGranted: widgetSharingGranted ?? this.widgetSharingGranted,
|
widgetSharingGranted: widgetSharingGranted ?? this.widgetSharingGranted,
|
||||||
twonlyScore: twonlyScore ?? this.twonlyScore,
|
twonlyScore: twonlyScore ?? this.twonlyScore,
|
||||||
|
joinedAt: joinedAt ?? this.joinedAt,
|
||||||
mediaSendCounter: mediaSendCounter ?? this.mediaSendCounter,
|
mediaSendCounter: mediaSendCounter ?? this.mediaSendCounter,
|
||||||
mediaReceivedCounter: mediaReceivedCounter ?? this.mediaReceivedCounter,
|
mediaReceivedCounter: mediaReceivedCounter ?? this.mediaReceivedCounter,
|
||||||
);
|
);
|
||||||
|
|
@ -1735,6 +1780,9 @@ class ContactsCompanion extends UpdateCompanion<Contact> {
|
||||||
if (twonlyScore.present) {
|
if (twonlyScore.present) {
|
||||||
map['twonly_score'] = Variable<int>(twonlyScore.value);
|
map['twonly_score'] = Variable<int>(twonlyScore.value);
|
||||||
}
|
}
|
||||||
|
if (joinedAt.present) {
|
||||||
|
map['joined_at'] = Variable<DateTime>(joinedAt.value);
|
||||||
|
}
|
||||||
if (mediaSendCounter.present) {
|
if (mediaSendCounter.present) {
|
||||||
map['media_send_counter'] = Variable<int>(mediaSendCounter.value);
|
map['media_send_counter'] = Variable<int>(mediaSendCounter.value);
|
||||||
}
|
}
|
||||||
|
|
@ -1776,6 +1824,7 @@ class ContactsCompanion extends UpdateCompanion<Contact> {
|
||||||
..write('widgetSharingAllowed: $widgetSharingAllowed, ')
|
..write('widgetSharingAllowed: $widgetSharingAllowed, ')
|
||||||
..write('widgetSharingGranted: $widgetSharingGranted, ')
|
..write('widgetSharingGranted: $widgetSharingGranted, ')
|
||||||
..write('twonlyScore: $twonlyScore, ')
|
..write('twonlyScore: $twonlyScore, ')
|
||||||
|
..write('joinedAt: $joinedAt, ')
|
||||||
..write('mediaSendCounter: $mediaSendCounter, ')
|
..write('mediaSendCounter: $mediaSendCounter, ')
|
||||||
..write('mediaReceivedCounter: $mediaReceivedCounter')
|
..write('mediaReceivedCounter: $mediaReceivedCounter')
|
||||||
..write(')'))
|
..write(')'))
|
||||||
|
|
@ -15812,6 +15861,7 @@ typedef $$ContactsTableCreateCompanionBuilder =
|
||||||
Value<bool> widgetSharingAllowed,
|
Value<bool> widgetSharingAllowed,
|
||||||
Value<bool> widgetSharingGranted,
|
Value<bool> widgetSharingGranted,
|
||||||
Value<int?> twonlyScore,
|
Value<int?> twonlyScore,
|
||||||
|
Value<DateTime?> joinedAt,
|
||||||
Value<int> mediaSendCounter,
|
Value<int> mediaSendCounter,
|
||||||
Value<int> mediaReceivedCounter,
|
Value<int> mediaReceivedCounter,
|
||||||
});
|
});
|
||||||
|
|
@ -15844,6 +15894,7 @@ typedef $$ContactsTableUpdateCompanionBuilder =
|
||||||
Value<bool> widgetSharingAllowed,
|
Value<bool> widgetSharingAllowed,
|
||||||
Value<bool> widgetSharingGranted,
|
Value<bool> widgetSharingGranted,
|
||||||
Value<int?> twonlyScore,
|
Value<int?> twonlyScore,
|
||||||
|
Value<DateTime?> joinedAt,
|
||||||
Value<int> mediaSendCounter,
|
Value<int> mediaSendCounter,
|
||||||
Value<int> mediaReceivedCounter,
|
Value<int> mediaReceivedCounter,
|
||||||
});
|
});
|
||||||
|
|
@ -16268,6 +16319,11 @@ class $$ContactsTableFilterComposer
|
||||||
builder: (column) => ColumnFilters(column),
|
builder: (column) => ColumnFilters(column),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
ColumnFilters<DateTime> get joinedAt => $composableBuilder(
|
||||||
|
column: $table.joinedAt,
|
||||||
|
builder: (column) => ColumnFilters(column),
|
||||||
|
);
|
||||||
|
|
||||||
ColumnFilters<int> get mediaSendCounter => $composableBuilder(
|
ColumnFilters<int> get mediaSendCounter => $composableBuilder(
|
||||||
column: $table.mediaSendCounter,
|
column: $table.mediaSendCounter,
|
||||||
builder: (column) => ColumnFilters(column),
|
builder: (column) => ColumnFilters(column),
|
||||||
|
|
@ -16733,6 +16789,11 @@ class $$ContactsTableOrderingComposer
|
||||||
builder: (column) => ColumnOrderings(column),
|
builder: (column) => ColumnOrderings(column),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
ColumnOrderings<DateTime> get joinedAt => $composableBuilder(
|
||||||
|
column: $table.joinedAt,
|
||||||
|
builder: (column) => ColumnOrderings(column),
|
||||||
|
);
|
||||||
|
|
||||||
ColumnOrderings<int> get mediaSendCounter => $composableBuilder(
|
ColumnOrderings<int> get mediaSendCounter => $composableBuilder(
|
||||||
column: $table.mediaSendCounter,
|
column: $table.mediaSendCounter,
|
||||||
builder: (column) => ColumnOrderings(column),
|
builder: (column) => ColumnOrderings(column),
|
||||||
|
|
@ -16875,6 +16936,9 @@ class $$ContactsTableAnnotationComposer
|
||||||
builder: (column) => column,
|
builder: (column) => column,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
GeneratedColumn<DateTime> get joinedAt =>
|
||||||
|
$composableBuilder(column: $table.joinedAt, builder: (column) => column);
|
||||||
|
|
||||||
GeneratedColumn<int> get mediaSendCounter => $composableBuilder(
|
GeneratedColumn<int> get mediaSendCounter => $composableBuilder(
|
||||||
column: $table.mediaSendCounter,
|
column: $table.mediaSendCounter,
|
||||||
builder: (column) => column,
|
builder: (column) => column,
|
||||||
|
|
@ -17270,6 +17334,7 @@ class $$ContactsTableTableManager
|
||||||
Value<bool> widgetSharingAllowed = const Value.absent(),
|
Value<bool> widgetSharingAllowed = const Value.absent(),
|
||||||
Value<bool> widgetSharingGranted = const Value.absent(),
|
Value<bool> widgetSharingGranted = const Value.absent(),
|
||||||
Value<int?> twonlyScore = const Value.absent(),
|
Value<int?> twonlyScore = const Value.absent(),
|
||||||
|
Value<DateTime?> joinedAt = const Value.absent(),
|
||||||
Value<int> mediaSendCounter = const Value.absent(),
|
Value<int> mediaSendCounter = const Value.absent(),
|
||||||
Value<int> mediaReceivedCounter = const Value.absent(),
|
Value<int> mediaReceivedCounter = const Value.absent(),
|
||||||
}) => ContactsCompanion(
|
}) => ContactsCompanion(
|
||||||
|
|
@ -17300,6 +17365,7 @@ class $$ContactsTableTableManager
|
||||||
widgetSharingAllowed: widgetSharingAllowed,
|
widgetSharingAllowed: widgetSharingAllowed,
|
||||||
widgetSharingGranted: widgetSharingGranted,
|
widgetSharingGranted: widgetSharingGranted,
|
||||||
twonlyScore: twonlyScore,
|
twonlyScore: twonlyScore,
|
||||||
|
joinedAt: joinedAt,
|
||||||
mediaSendCounter: mediaSendCounter,
|
mediaSendCounter: mediaSendCounter,
|
||||||
mediaReceivedCounter: mediaReceivedCounter,
|
mediaReceivedCounter: mediaReceivedCounter,
|
||||||
),
|
),
|
||||||
|
|
@ -17334,6 +17400,7 @@ class $$ContactsTableTableManager
|
||||||
Value<bool> widgetSharingAllowed = const Value.absent(),
|
Value<bool> widgetSharingAllowed = const Value.absent(),
|
||||||
Value<bool> widgetSharingGranted = const Value.absent(),
|
Value<bool> widgetSharingGranted = const Value.absent(),
|
||||||
Value<int?> twonlyScore = const Value.absent(),
|
Value<int?> twonlyScore = const Value.absent(),
|
||||||
|
Value<DateTime?> joinedAt = const Value.absent(),
|
||||||
Value<int> mediaSendCounter = const Value.absent(),
|
Value<int> mediaSendCounter = const Value.absent(),
|
||||||
Value<int> mediaReceivedCounter = const Value.absent(),
|
Value<int> mediaReceivedCounter = const Value.absent(),
|
||||||
}) => ContactsCompanion.insert(
|
}) => ContactsCompanion.insert(
|
||||||
|
|
@ -17364,6 +17431,7 @@ class $$ContactsTableTableManager
|
||||||
widgetSharingAllowed: widgetSharingAllowed,
|
widgetSharingAllowed: widgetSharingAllowed,
|
||||||
widgetSharingGranted: widgetSharingGranted,
|
widgetSharingGranted: widgetSharingGranted,
|
||||||
twonlyScore: twonlyScore,
|
twonlyScore: twonlyScore,
|
||||||
|
joinedAt: joinedAt,
|
||||||
mediaSendCounter: mediaSendCounter,
|
mediaSendCounter: mediaSendCounter,
|
||||||
mediaReceivedCounter: mediaReceivedCounter,
|
mediaReceivedCounter: mediaReceivedCounter,
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -682,6 +682,30 @@ abstract class AppLocalizations {
|
||||||
/// **'The twonly Score reflects a person\'s activity on twonly. It is calculated from several factors, such as how many photos and videos they send and receive.'**
|
/// **'The twonly Score reflects a person\'s activity on twonly. It is calculated from several factors, such as how many photos and videos they send and receive.'**
|
||||||
String get contactTwonlyScoreDescription;
|
String get contactTwonlyScoreDescription;
|
||||||
|
|
||||||
|
/// No description provided for @contactJoinedToday.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Joined today'**
|
||||||
|
String get contactJoinedToday;
|
||||||
|
|
||||||
|
/// No description provided for @contactJoinedDaysAgo.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'{days, plural, =1{Joined 1 day ago} other{Joined {days} days ago}}'**
|
||||||
|
String contactJoinedDaysAgo(num days);
|
||||||
|
|
||||||
|
/// No description provided for @contactJoinedMonthsAgo.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'{months, plural, =1{Joined 1 month ago} other{Joined {months} months ago}}'**
|
||||||
|
String contactJoinedMonthsAgo(num months);
|
||||||
|
|
||||||
|
/// No description provided for @contactJoinedYearsAgo.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'{years, plural, =1{Joined 1 year ago} other{Joined {years} years ago}}'**
|
||||||
|
String contactJoinedYearsAgo(num years);
|
||||||
|
|
||||||
/// No description provided for @privacyVisibilityNobody.
|
/// No description provided for @privacyVisibilityNobody.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
|
|
@ -5169,6 +5193,96 @@ abstract class AppLocalizations {
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Delete sticker'**
|
/// **'Delete sticker'**
|
||||||
String get deleteSticker;
|
String get deleteSticker;
|
||||||
|
|
||||||
|
/// No description provided for @releaseNotesTitle.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'What\'s new'**
|
||||||
|
String get releaseNotesTitle;
|
||||||
|
|
||||||
|
/// No description provided for @releaseNotesIntroduction.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'The biggest twonly update yet is here. Here\'s a quick look at what\'s new.'**
|
||||||
|
String get releaseNotesIntroduction;
|
||||||
|
|
||||||
|
/// No description provided for @releaseNotesAlsoImproved.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Also improved'**
|
||||||
|
String get releaseNotesAlsoImproved;
|
||||||
|
|
||||||
|
/// No description provided for @releaseNotesStickers.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Stickers'**
|
||||||
|
String get releaseNotesStickers;
|
||||||
|
|
||||||
|
/// No description provided for @releaseNotesStickersDescription.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Turn your photos into stickers and share them in chats.'**
|
||||||
|
String get releaseNotesStickersDescription;
|
||||||
|
|
||||||
|
/// No description provided for @releaseNotesWidgets.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Widgets'**
|
||||||
|
String get releaseNotesWidgets;
|
||||||
|
|
||||||
|
/// No description provided for @releaseNotesWidgetsDescription.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'See fresh photos from your favorite people right on your home screen.'**
|
||||||
|
String get releaseNotesWidgetsDescription;
|
||||||
|
|
||||||
|
/// No description provided for @releaseNotesStories.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Stories'**
|
||||||
|
String get releaseNotesStories;
|
||||||
|
|
||||||
|
/// No description provided for @releaseNotesStoriesDescription.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Share moments with your contacts for 24 hours.'**
|
||||||
|
String get releaseNotesStoriesDescription;
|
||||||
|
|
||||||
|
/// No description provided for @releaseNotesMiniGames.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Mini games in chats & groups'**
|
||||||
|
String get releaseNotesMiniGames;
|
||||||
|
|
||||||
|
/// No description provided for @releaseNotesMiniGamesDescription.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Play small games together, right inside your conversations.'**
|
||||||
|
String get releaseNotesMiniGamesDescription;
|
||||||
|
|
||||||
|
/// No description provided for @releaseNotesReliableMessages.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Better message and push reliability'**
|
||||||
|
String get releaseNotesReliableMessages;
|
||||||
|
|
||||||
|
/// No description provided for @releaseNotesImprovedUi.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Improved interface'**
|
||||||
|
String get releaseNotesImprovedUi;
|
||||||
|
|
||||||
|
/// No description provided for @releaseNotesCustomAvatars.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Custom avatars'**
|
||||||
|
String get releaseNotesCustomAvatars;
|
||||||
|
|
||||||
|
/// No description provided for @releaseNotesArabic.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Arabic language (experimental)'**
|
||||||
|
String get releaseNotesArabic;
|
||||||
}
|
}
|
||||||
|
|
||||||
class _AppLocalizationsDelegate
|
class _AppLocalizationsDelegate
|
||||||
|
|
|
||||||
|
|
@ -316,6 +316,51 @@ class AppLocalizationsAr extends AppLocalizations {
|
||||||
String get contactTwonlyScoreDescription =>
|
String get contactTwonlyScoreDescription =>
|
||||||
'تعكس نقاط twonly نشاط الشخص على twonly. ويتم احتسابها استنادًا إلى عدة عوامل، مثل عدد الصور ومقاطع الفيديو التي يرسلها ويستلمها.';
|
'تعكس نقاط twonly نشاط الشخص على twonly. ويتم احتسابها استنادًا إلى عدة عوامل، مثل عدد الصور ومقاطع الفيديو التي يرسلها ويستلمها.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get contactJoinedToday => 'انضم اليوم';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String contactJoinedDaysAgo(num days) {
|
||||||
|
String _temp0 = intl.Intl.pluralLogic(
|
||||||
|
days,
|
||||||
|
locale: localeName,
|
||||||
|
other: 'انضم منذ $days يوم',
|
||||||
|
many: 'انضم منذ $days يومًا',
|
||||||
|
few: 'انضم منذ $days أيام',
|
||||||
|
two: 'انضم منذ يومين',
|
||||||
|
one: 'انضم منذ يوم واحد',
|
||||||
|
);
|
||||||
|
return '$_temp0';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String contactJoinedMonthsAgo(num months) {
|
||||||
|
String _temp0 = intl.Intl.pluralLogic(
|
||||||
|
months,
|
||||||
|
locale: localeName,
|
||||||
|
other: 'انضم منذ $months شهر',
|
||||||
|
many: 'انضم منذ $months شهرًا',
|
||||||
|
few: 'انضم منذ $months أشهر',
|
||||||
|
two: 'انضم منذ شهرين',
|
||||||
|
one: 'انضم منذ شهر واحد',
|
||||||
|
);
|
||||||
|
return '$_temp0';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String contactJoinedYearsAgo(num years) {
|
||||||
|
String _temp0 = intl.Intl.pluralLogic(
|
||||||
|
years,
|
||||||
|
locale: localeName,
|
||||||
|
other: 'انضم منذ $years سنة',
|
||||||
|
many: 'انضم منذ $years سنة',
|
||||||
|
few: 'انضم منذ $years سنوات',
|
||||||
|
two: 'انضم منذ سنتين',
|
||||||
|
one: 'انضم منذ سنة واحدة',
|
||||||
|
);
|
||||||
|
return '$_temp0';
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get privacyVisibilityNobody => 'لا أحد';
|
String get privacyVisibilityNobody => 'لا أحد';
|
||||||
|
|
||||||
|
|
@ -3043,4 +3088,54 @@ class AppLocalizationsAr extends AppLocalizations {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get deleteSticker => 'حذف الملصق';
|
String get deleteSticker => 'حذف الملصق';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get releaseNotesTitle => 'ما الجديد؟';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get releaseNotesIntroduction =>
|
||||||
|
'وصل أكبر تحديث لـ twonly حتى الآن. إليك نظرة سريعة على الجديد.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get releaseNotesAlsoImproved => 'تحسينات أخرى';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get releaseNotesStickers => 'الملصقات';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get releaseNotesStickersDescription =>
|
||||||
|
'حوّل صورك إلى ملصقات وشاركها في المحادثات.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get releaseNotesWidgets => 'الأدوات';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get releaseNotesWidgetsDescription =>
|
||||||
|
'شاهد أحدث صور الأشخاص المفضلين لديك مباشرة على شاشتك الرئيسية.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get releaseNotesStories => 'القصص';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get releaseNotesStoriesDescription =>
|
||||||
|
'شارك لحظاتك مع جهات اتصالك لمدة 24 ساعة.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get releaseNotesMiniGames => 'ألعاب مصغّرة في المحادثات والمجموعات';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get releaseNotesMiniGamesDescription =>
|
||||||
|
'العبوا ألعابًا صغيرة معًا داخل محادثاتكم مباشرة.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get releaseNotesReliableMessages => 'موثوقية أفضل للرسائل والإشعارات';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get releaseNotesImprovedUi => 'واجهة مستخدم محسّنة';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get releaseNotesCustomAvatars => 'صور رمزية مخصّصة';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get releaseNotesArabic => 'اللغة العربية (تجريبية)';
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -319,6 +319,42 @@ class AppLocalizationsDe extends AppLocalizations {
|
||||||
String get contactTwonlyScoreDescription =>
|
String get contactTwonlyScoreDescription =>
|
||||||
'Der twonly Score spiegelt die Aktivität einer Person auf twonly wider. Er wird aus verschiedenen Faktoren berechnet, zum Beispiel daraus, wie viele Fotos und Videos sie sendet und empfängt.';
|
'Der twonly Score spiegelt die Aktivität einer Person auf twonly wider. Er wird aus verschiedenen Faktoren berechnet, zum Beispiel daraus, wie viele Fotos und Videos sie sendet und empfängt.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get contactJoinedToday => 'Heute beigetreten';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String contactJoinedDaysAgo(num days) {
|
||||||
|
String _temp0 = intl.Intl.pluralLogic(
|
||||||
|
days,
|
||||||
|
locale: localeName,
|
||||||
|
other: 'Vor $days Tagen beigetreten',
|
||||||
|
one: 'Vor 1 Tag beigetreten',
|
||||||
|
);
|
||||||
|
return '$_temp0';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String contactJoinedMonthsAgo(num months) {
|
||||||
|
String _temp0 = intl.Intl.pluralLogic(
|
||||||
|
months,
|
||||||
|
locale: localeName,
|
||||||
|
other: 'Vor $months Monaten beigetreten',
|
||||||
|
one: 'Vor 1 Monat beigetreten',
|
||||||
|
);
|
||||||
|
return '$_temp0';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String contactJoinedYearsAgo(num years) {
|
||||||
|
String _temp0 = intl.Intl.pluralLogic(
|
||||||
|
years,
|
||||||
|
locale: localeName,
|
||||||
|
other: 'Vor $years Jahren beigetreten',
|
||||||
|
one: 'Vor 1 Jahr beigetreten',
|
||||||
|
);
|
||||||
|
return '$_temp0';
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get privacyVisibilityNobody => 'Niemand';
|
String get privacyVisibilityNobody => 'Niemand';
|
||||||
|
|
||||||
|
|
@ -3045,4 +3081,55 @@ class AppLocalizationsDe extends AppLocalizations {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get deleteSticker => 'Sticker löschen';
|
String get deleteSticker => 'Sticker löschen';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get releaseNotesTitle => 'Was ist neu?';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get releaseNotesIntroduction =>
|
||||||
|
'Das bisher größte twonly-Update ist da. Hier ist ein kurzer Überblick.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get releaseNotesAlsoImproved => 'Außerdem verbessert';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get releaseNotesStickers => 'Sticker';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get releaseNotesStickersDescription =>
|
||||||
|
'Erstelle Sticker aus deinen Fotos und teile sie in Chats.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get releaseNotesWidgets => 'Widgets';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get releaseNotesWidgetsDescription =>
|
||||||
|
'Sieh neue Fotos deiner Lieblingsmenschen direkt auf dem Homescreen.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get releaseNotesStories => 'Storys';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get releaseNotesStoriesDescription =>
|
||||||
|
'Teile Momente für 24 Stunden mit deinen Kontakten.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get releaseNotesMiniGames => 'Minispiele in Chats & Gruppen';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get releaseNotesMiniGamesDescription =>
|
||||||
|
'Spielt kleine Spiele gemeinsam direkt in euren Unterhaltungen.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get releaseNotesReliableMessages =>
|
||||||
|
'Zuverlässigere Nachrichten und Push-Benachrichtigungen';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get releaseNotesImprovedUi => 'Verbesserte Benutzeroberfläche';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get releaseNotesCustomAvatars => 'Individuelle Avatare';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get releaseNotesArabic => 'Arabische Sprache (experimentell)';
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -316,6 +316,42 @@ class AppLocalizationsEn extends AppLocalizations {
|
||||||
String get contactTwonlyScoreDescription =>
|
String get contactTwonlyScoreDescription =>
|
||||||
'The twonly Score reflects a person\'s activity on twonly. It is calculated from several factors, such as how many photos and videos they send and receive.';
|
'The twonly Score reflects a person\'s activity on twonly. It is calculated from several factors, such as how many photos and videos they send and receive.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get contactJoinedToday => 'Joined today';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String contactJoinedDaysAgo(num days) {
|
||||||
|
String _temp0 = intl.Intl.pluralLogic(
|
||||||
|
days,
|
||||||
|
locale: localeName,
|
||||||
|
other: 'Joined $days days ago',
|
||||||
|
one: 'Joined 1 day ago',
|
||||||
|
);
|
||||||
|
return '$_temp0';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String contactJoinedMonthsAgo(num months) {
|
||||||
|
String _temp0 = intl.Intl.pluralLogic(
|
||||||
|
months,
|
||||||
|
locale: localeName,
|
||||||
|
other: 'Joined $months months ago',
|
||||||
|
one: 'Joined 1 month ago',
|
||||||
|
);
|
||||||
|
return '$_temp0';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String contactJoinedYearsAgo(num years) {
|
||||||
|
String _temp0 = intl.Intl.pluralLogic(
|
||||||
|
years,
|
||||||
|
locale: localeName,
|
||||||
|
other: 'Joined $years years ago',
|
||||||
|
one: 'Joined 1 year ago',
|
||||||
|
);
|
||||||
|
return '$_temp0';
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get privacyVisibilityNobody => 'Nobody';
|
String get privacyVisibilityNobody => 'Nobody';
|
||||||
|
|
||||||
|
|
@ -3014,4 +3050,55 @@ class AppLocalizationsEn extends AppLocalizations {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get deleteSticker => 'Delete sticker';
|
String get deleteSticker => 'Delete sticker';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get releaseNotesTitle => 'What\'s new';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get releaseNotesIntroduction =>
|
||||||
|
'The biggest twonly update yet is here. Here\'s a quick look at what\'s new.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get releaseNotesAlsoImproved => 'Also improved';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get releaseNotesStickers => 'Stickers';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get releaseNotesStickersDescription =>
|
||||||
|
'Turn your photos into stickers and share them in chats.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get releaseNotesWidgets => 'Widgets';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get releaseNotesWidgetsDescription =>
|
||||||
|
'See fresh photos from your favorite people right on your home screen.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get releaseNotesStories => 'Stories';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get releaseNotesStoriesDescription =>
|
||||||
|
'Share moments with your contacts for 24 hours.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get releaseNotesMiniGames => 'Mini games in chats & groups';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get releaseNotesMiniGamesDescription =>
|
||||||
|
'Play small games together, right inside your conversations.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get releaseNotesReliableMessages =>
|
||||||
|
'Better message and push reliability';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get releaseNotesImprovedUi => 'Improved interface';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get releaseNotesCustomAvatars => 'Custom avatars';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get releaseNotesArabic => 'Arabic language (experimental)';
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -97,6 +97,10 @@
|
||||||
"publicProfilePrivacyDescription": "اختر من يمكنه رؤية معلومات ملفك الشخصي.",
|
"publicProfilePrivacyDescription": "اختر من يمكنه رؤية معلومات ملفك الشخصي.",
|
||||||
"publicProfileTwonlyScore": "نقاط twonly",
|
"publicProfileTwonlyScore": "نقاط twonly",
|
||||||
"contactTwonlyScoreDescription": "تعكس نقاط twonly نشاط الشخص على twonly. ويتم احتسابها استنادًا إلى عدة عوامل، مثل عدد الصور ومقاطع الفيديو التي يرسلها ويستلمها.",
|
"contactTwonlyScoreDescription": "تعكس نقاط twonly نشاط الشخص على twonly. ويتم احتسابها استنادًا إلى عدة عوامل، مثل عدد الصور ومقاطع الفيديو التي يرسلها ويستلمها.",
|
||||||
|
"contactJoinedToday": "انضم اليوم",
|
||||||
|
"contactJoinedDaysAgo": "{days, plural, =1{انضم منذ يوم واحد} =2{انضم منذ يومين} few{انضم منذ {days} أيام} many{انضم منذ {days} يومًا} other{انضم منذ {days} يوم}}",
|
||||||
|
"contactJoinedMonthsAgo": "{months, plural, =1{انضم منذ شهر واحد} =2{انضم منذ شهرين} few{انضم منذ {months} أشهر} many{انضم منذ {months} شهرًا} other{انضم منذ {months} شهر}}",
|
||||||
|
"contactJoinedYearsAgo": "{years, plural, =1{انضم منذ سنة واحدة} =2{انضم منذ سنتين} few{انضم منذ {years} سنوات} many{انضم منذ {years} سنة} other{انضم منذ {years} سنة}}",
|
||||||
"privacyVisibilityNobody": "لا أحد",
|
"privacyVisibilityNobody": "لا أحد",
|
||||||
"privacyVisibilityOnlyContacts": "جهات الاتصال فقط",
|
"privacyVisibilityOnlyContacts": "جهات الاتصال فقط",
|
||||||
"privacyVisibilityEveryone": "الجميع",
|
"privacyVisibilityEveryone": "الجميع",
|
||||||
|
|
@ -865,5 +869,20 @@
|
||||||
"notificationSticker": "أرسل ملصقًا{inGroup}.",
|
"notificationSticker": "أرسل ملصقًا{inGroup}.",
|
||||||
"storeSticker": "حفظ الملصق",
|
"storeSticker": "حفظ الملصق",
|
||||||
"removeSticker": "إزالة من المجموعة",
|
"removeSticker": "إزالة من المجموعة",
|
||||||
"deleteSticker": "حذف الملصق"
|
"deleteSticker": "حذف الملصق",
|
||||||
|
"releaseNotesTitle": "ما الجديد؟",
|
||||||
|
"releaseNotesIntroduction": "وصل أكبر تحديث لـ twonly حتى الآن. إليك نظرة سريعة على الجديد.",
|
||||||
|
"releaseNotesAlsoImproved": "تحسينات أخرى",
|
||||||
|
"releaseNotesStickers": "الملصقات",
|
||||||
|
"releaseNotesStickersDescription": "حوّل صورك إلى ملصقات وشاركها في المحادثات.",
|
||||||
|
"releaseNotesWidgets": "الأدوات",
|
||||||
|
"releaseNotesWidgetsDescription": "شاهد أحدث صور الأشخاص المفضلين لديك مباشرة على شاشتك الرئيسية.",
|
||||||
|
"releaseNotesStories": "القصص",
|
||||||
|
"releaseNotesStoriesDescription": "شارك لحظاتك مع جهات اتصالك لمدة 24 ساعة.",
|
||||||
|
"releaseNotesMiniGames": "ألعاب مصغّرة في المحادثات والمجموعات",
|
||||||
|
"releaseNotesMiniGamesDescription": "العبوا ألعابًا صغيرة معًا داخل محادثاتكم مباشرة.",
|
||||||
|
"releaseNotesReliableMessages": "موثوقية أفضل للرسائل والإشعارات",
|
||||||
|
"releaseNotesImprovedUi": "واجهة مستخدم محسّنة",
|
||||||
|
"releaseNotesCustomAvatars": "صور رمزية مخصّصة",
|
||||||
|
"releaseNotesArabic": "اللغة العربية (تجريبية)"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -106,6 +106,10 @@
|
||||||
"publicProfilePrivacyDescription": "Wähle aus, wer Informationen über dein Profil sehen kann.",
|
"publicProfilePrivacyDescription": "Wähle aus, wer Informationen über dein Profil sehen kann.",
|
||||||
"publicProfileTwonlyScore": "twonly Score",
|
"publicProfileTwonlyScore": "twonly Score",
|
||||||
"contactTwonlyScoreDescription": "Der twonly Score spiegelt die Aktivität einer Person auf twonly wider. Er wird aus verschiedenen Faktoren berechnet, zum Beispiel daraus, wie viele Fotos und Videos sie sendet und empfängt.",
|
"contactTwonlyScoreDescription": "Der twonly Score spiegelt die Aktivität einer Person auf twonly wider. Er wird aus verschiedenen Faktoren berechnet, zum Beispiel daraus, wie viele Fotos und Videos sie sendet und empfängt.",
|
||||||
|
"contactJoinedToday": "Heute beigetreten",
|
||||||
|
"contactJoinedDaysAgo": "{days, plural, =1{Vor 1 Tag beigetreten} other{Vor {days} Tagen beigetreten}}",
|
||||||
|
"contactJoinedMonthsAgo": "{months, plural, =1{Vor 1 Monat beigetreten} other{Vor {months} Monaten beigetreten}}",
|
||||||
|
"contactJoinedYearsAgo": "{years, plural, =1{Vor 1 Jahr beigetreten} other{Vor {years} Jahren beigetreten}}",
|
||||||
"privacyVisibilityNobody": "Niemand",
|
"privacyVisibilityNobody": "Niemand",
|
||||||
"privacyVisibilityOnlyContacts": "Nur Kontakte",
|
"privacyVisibilityOnlyContacts": "Nur Kontakte",
|
||||||
"privacyVisibilityEveryone": "Alle",
|
"privacyVisibilityEveryone": "Alle",
|
||||||
|
|
@ -1178,5 +1182,20 @@
|
||||||
"notificationSticker": "hat einen Sticker gesendet{inGroup}.",
|
"notificationSticker": "hat einen Sticker gesendet{inGroup}.",
|
||||||
"storeSticker": "Sticker speichern",
|
"storeSticker": "Sticker speichern",
|
||||||
"removeSticker": "Aus Sammlung entfernen",
|
"removeSticker": "Aus Sammlung entfernen",
|
||||||
"deleteSticker": "Sticker löschen"
|
"deleteSticker": "Sticker löschen",
|
||||||
|
"releaseNotesTitle": "Was ist neu?",
|
||||||
|
"releaseNotesIntroduction": "Das bisher größte twonly-Update ist da. Hier ist ein kurzer Überblick.",
|
||||||
|
"releaseNotesAlsoImproved": "Außerdem verbessert",
|
||||||
|
"releaseNotesStickers": "Sticker",
|
||||||
|
"releaseNotesStickersDescription": "Erstelle Sticker aus deinen Fotos und teile sie in Chats.",
|
||||||
|
"releaseNotesWidgets": "Widgets",
|
||||||
|
"releaseNotesWidgetsDescription": "Sieh neue Fotos deiner Lieblingsmenschen direkt auf dem Homescreen.",
|
||||||
|
"releaseNotesStories": "Storys",
|
||||||
|
"releaseNotesStoriesDescription": "Teile Momente für 24 Stunden mit deinen Kontakten.",
|
||||||
|
"releaseNotesMiniGames": "Minispiele in Chats & Gruppen",
|
||||||
|
"releaseNotesMiniGamesDescription": "Spielt kleine Spiele gemeinsam direkt in euren Unterhaltungen.",
|
||||||
|
"releaseNotesReliableMessages": "Zuverlässigere Nachrichten und Push-Benachrichtigungen",
|
||||||
|
"releaseNotesImprovedUi": "Verbesserte Benutzeroberfläche",
|
||||||
|
"releaseNotesCustomAvatars": "Individuelle Avatare",
|
||||||
|
"releaseNotesArabic": "Arabische Sprache (experimentell)"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -102,6 +102,10 @@
|
||||||
"publicProfilePrivacyDescription": "Choose who can see information about your profile.",
|
"publicProfilePrivacyDescription": "Choose who can see information about your profile.",
|
||||||
"publicProfileTwonlyScore": "twonly Score",
|
"publicProfileTwonlyScore": "twonly Score",
|
||||||
"contactTwonlyScoreDescription": "The twonly Score reflects a person's activity on twonly. It is calculated from several factors, such as how many photos and videos they send and receive.",
|
"contactTwonlyScoreDescription": "The twonly Score reflects a person's activity on twonly. It is calculated from several factors, such as how many photos and videos they send and receive.",
|
||||||
|
"contactJoinedToday": "Joined today",
|
||||||
|
"contactJoinedDaysAgo": "{days, plural, =1{Joined 1 day ago} other{Joined {days} days ago}}",
|
||||||
|
"contactJoinedMonthsAgo": "{months, plural, =1{Joined 1 month ago} other{Joined {months} months ago}}",
|
||||||
|
"contactJoinedYearsAgo": "{years, plural, =1{Joined 1 year ago} other{Joined {years} years ago}}",
|
||||||
"privacyVisibilityNobody": "Nobody",
|
"privacyVisibilityNobody": "Nobody",
|
||||||
"privacyVisibilityOnlyContacts": "Only Contacts",
|
"privacyVisibilityOnlyContacts": "Only Contacts",
|
||||||
"privacyVisibilityEveryone": "Everyone",
|
"privacyVisibilityEveryone": "Everyone",
|
||||||
|
|
@ -1188,5 +1192,20 @@
|
||||||
"notificationSticker": "sent a sticker{inGroup}.",
|
"notificationSticker": "sent a sticker{inGroup}.",
|
||||||
"storeSticker": "Save sticker",
|
"storeSticker": "Save sticker",
|
||||||
"removeSticker": "Remove from collection",
|
"removeSticker": "Remove from collection",
|
||||||
"deleteSticker": "Delete sticker"
|
"deleteSticker": "Delete sticker",
|
||||||
|
"releaseNotesTitle": "What's new",
|
||||||
|
"releaseNotesIntroduction": "The biggest twonly update yet is here. Here's a quick look at what's new.",
|
||||||
|
"releaseNotesAlsoImproved": "Also improved",
|
||||||
|
"releaseNotesStickers": "Stickers",
|
||||||
|
"releaseNotesStickersDescription": "Turn your photos into stickers and share them in chats.",
|
||||||
|
"releaseNotesWidgets": "Widgets",
|
||||||
|
"releaseNotesWidgetsDescription": "See fresh photos from your favorite people right on your home screen.",
|
||||||
|
"releaseNotesStories": "Stories",
|
||||||
|
"releaseNotesStoriesDescription": "Share moments with your contacts for 24 hours.",
|
||||||
|
"releaseNotesMiniGames": "Mini games in chats & groups",
|
||||||
|
"releaseNotesMiniGamesDescription": "Play small games together, right inside your conversations.",
|
||||||
|
"releaseNotesReliableMessages": "Better message and push reliability",
|
||||||
|
"releaseNotesImprovedUi": "Improved interface",
|
||||||
|
"releaseNotesCustomAvatars": "Custom avatars",
|
||||||
|
"releaseNotesArabic": "Arabic language (experimental)"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -68,6 +68,10 @@ class ApiService {
|
||||||
rust_api.RustApi.reuploadPendingMedia(),
|
rust_api.RustApi.reuploadPendingMedia(),
|
||||||
'reuploadPendingMedia',
|
'reuploadPendingMedia',
|
||||||
);
|
);
|
||||||
|
unawaitedRustCall(
|
||||||
|
rust_api.RustApi.refreshContactJoinedDates(),
|
||||||
|
'refreshContactJoinedDates',
|
||||||
|
);
|
||||||
|
|
||||||
twonlyDB.markUpdated();
|
twonlyDB.markUpdated();
|
||||||
// resetUserDiscoveryRequestUpdates();
|
// resetUserDiscoveryRequestUpdates();
|
||||||
|
|
|
||||||
|
|
@ -99,6 +99,22 @@ String formatDuration(BuildContext context, int seconds) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String formatJoinedAt(BuildContext context, DateTime joinedAt) {
|
||||||
|
final elapsed = clock.now().toUtc().difference(joinedAt.toUtc());
|
||||||
|
final days = max(0, elapsed.inDays);
|
||||||
|
|
||||||
|
if (days == 0) {
|
||||||
|
return context.lang.contactJoinedToday;
|
||||||
|
}
|
||||||
|
if (days < 30) {
|
||||||
|
return context.lang.contactJoinedDaysAgo(days);
|
||||||
|
}
|
||||||
|
if (days < 365) {
|
||||||
|
return context.lang.contactJoinedMonthsAgo(days ~/ 30);
|
||||||
|
}
|
||||||
|
return context.lang.contactJoinedYearsAgo(days ~/ 365);
|
||||||
|
}
|
||||||
|
|
||||||
Future<bool> authenticateUser(
|
Future<bool> authenticateUser(
|
||||||
String localizedReason, {
|
String localizedReason, {
|
||||||
bool force = true,
|
bool force = true,
|
||||||
|
|
|
||||||
312
lib/src/visual/components/release_notes.comp.dart
Normal file
312
lib/src/visual/components/release_notes.comp.dart
Normal file
|
|
@ -0,0 +1,312 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:twonly/locator.dart';
|
||||||
|
import 'package:twonly/src/services/user.service.dart';
|
||||||
|
import 'package:twonly/src/utils/misc.dart';
|
||||||
|
import 'package:twonly/src/visual/elements/my_button.element.dart';
|
||||||
|
|
||||||
|
@immutable
|
||||||
|
class ReleaseNoteFeature {
|
||||||
|
const ReleaseNoteFeature({
|
||||||
|
required this.icon,
|
||||||
|
required this.title,
|
||||||
|
required this.description,
|
||||||
|
});
|
||||||
|
|
||||||
|
final Widget icon;
|
||||||
|
final String title;
|
||||||
|
final String description;
|
||||||
|
}
|
||||||
|
|
||||||
|
@immutable
|
||||||
|
class ReleaseNotesData {
|
||||||
|
const ReleaseNotesData({
|
||||||
|
required this.version,
|
||||||
|
required this.title,
|
||||||
|
required this.introduction,
|
||||||
|
required this.additionalChangesTitle,
|
||||||
|
required this.closeLabel,
|
||||||
|
required this.features,
|
||||||
|
required this.additionalChanges,
|
||||||
|
});
|
||||||
|
|
||||||
|
final String version;
|
||||||
|
final String title;
|
||||||
|
final String introduction;
|
||||||
|
final String additionalChangesTitle;
|
||||||
|
final String closeLabel;
|
||||||
|
final List<ReleaseNoteFeature> features;
|
||||||
|
final List<String> additionalChanges;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Coordinates the once-per-version behavior for any release note.
|
||||||
|
class ReleaseNotesPresenter {
|
||||||
|
ReleaseNotesPresenter._();
|
||||||
|
|
||||||
|
static final Set<String> _showingVersions = {};
|
||||||
|
static final Set<String> _shownThisSession = {};
|
||||||
|
|
||||||
|
static Future<void> showIfNeeded(
|
||||||
|
BuildContext context,
|
||||||
|
ReleaseNotesData releaseNotes,
|
||||||
|
) async {
|
||||||
|
final version = releaseNotes.version;
|
||||||
|
if (_showingVersions.contains(version) ||
|
||||||
|
_shownThisSession.contains(version) ||
|
||||||
|
userService.currentUser.lastReleaseNotesVersion == version) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_showingVersions.add(version);
|
||||||
|
try {
|
||||||
|
await showReleaseNotesBottomSheet(context, releaseNotes);
|
||||||
|
_shownThisSession.add(version);
|
||||||
|
await UserService.update(
|
||||||
|
(user) => user.lastReleaseNotesVersion = version,
|
||||||
|
);
|
||||||
|
} finally {
|
||||||
|
_showingVersions.remove(version);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> showReleaseNotesBottomSheet(
|
||||||
|
BuildContext context,
|
||||||
|
ReleaseNotesData releaseNotes,
|
||||||
|
) {
|
||||||
|
return showModalBottomSheet<void>(
|
||||||
|
context: context,
|
||||||
|
useRootNavigator: true,
|
||||||
|
isScrollControlled: true,
|
||||||
|
backgroundColor: Colors.transparent,
|
||||||
|
builder: (context) => FractionallySizedBox(
|
||||||
|
heightFactor: 0.8,
|
||||||
|
child: ReleaseNotesBottomSheet(releaseNotes: releaseNotes),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
class ReleaseNotesBottomSheet extends StatelessWidget {
|
||||||
|
const ReleaseNotesBottomSheet({
|
||||||
|
required this.releaseNotes,
|
||||||
|
super.key,
|
||||||
|
});
|
||||||
|
|
||||||
|
final ReleaseNotesData releaseNotes;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Material(
|
||||||
|
color: context.color.surface,
|
||||||
|
clipBehavior: Clip.antiAlias,
|
||||||
|
shape: const RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.vertical(top: Radius.circular(28)),
|
||||||
|
),
|
||||||
|
child: SafeArea(
|
||||||
|
top: false,
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
const _DragHandle(),
|
||||||
|
Expanded(
|
||||||
|
child: ListView(
|
||||||
|
padding: const EdgeInsets.fromLTRB(20, 8, 20, 20),
|
||||||
|
children: [
|
||||||
|
_Header(releaseNotes: releaseNotes),
|
||||||
|
const SizedBox(height: 24),
|
||||||
|
...releaseNotes.features.map(
|
||||||
|
(feature) => Padding(
|
||||||
|
padding: const EdgeInsets.only(bottom: 12),
|
||||||
|
child: _FeatureCard(feature: feature),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (releaseNotes.additionalChanges.isNotEmpty) ...[
|
||||||
|
const SizedBox(height: 10),
|
||||||
|
Text(
|
||||||
|
releaseNotes.additionalChangesTitle,
|
||||||
|
style: Theme.of(context).textTheme.titleSmall?.copyWith(
|
||||||
|
color: context.color.onSurfaceVariant,
|
||||||
|
fontWeight: FontWeight.w700,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 10),
|
||||||
|
...releaseNotes.additionalChanges.map(
|
||||||
|
(change) => _AdditionalChange(text: change),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.fromLTRB(20, 8, 20, 12),
|
||||||
|
child: MyButton(
|
||||||
|
onPressed: () => Navigator.pop(context),
|
||||||
|
child: Text(releaseNotes.closeLabel),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _DragHandle extends StatelessWidget {
|
||||||
|
const _DragHandle();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
width: 42,
|
||||||
|
height: 4,
|
||||||
|
margin: const EdgeInsets.symmetric(vertical: 12),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: context.color.outlineVariant,
|
||||||
|
borderRadius: BorderRadius.circular(2),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _Header extends StatelessWidget {
|
||||||
|
const _Header({required this.releaseNotes});
|
||||||
|
|
||||||
|
final ReleaseNotesData releaseNotes;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
DecoratedBox(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: context.color.primaryContainer,
|
||||||
|
borderRadius: BorderRadius.circular(999),
|
||||||
|
),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
|
||||||
|
child: Text(
|
||||||
|
'v${releaseNotes.version}',
|
||||||
|
style: Theme.of(context).textTheme.labelMedium?.copyWith(
|
||||||
|
color: context.color.onPrimaryContainer,
|
||||||
|
fontWeight: FontWeight.w700,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 12),
|
||||||
|
Text(
|
||||||
|
releaseNotes.title,
|
||||||
|
style: Theme.of(context).textTheme.headlineSmall?.copyWith(
|
||||||
|
fontWeight: FontWeight.w800,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 6),
|
||||||
|
Text(
|
||||||
|
releaseNotes.introduction,
|
||||||
|
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
||||||
|
color: context.color.onSurfaceVariant,
|
||||||
|
height: 1.35,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _FeatureCard extends StatelessWidget {
|
||||||
|
const _FeatureCard({required this.feature});
|
||||||
|
|
||||||
|
final ReleaseNoteFeature feature;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return DecoratedBox(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: context.color.surfaceContainerLow,
|
||||||
|
borderRadius: BorderRadius.circular(18),
|
||||||
|
),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(14),
|
||||||
|
child: Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
width: 44,
|
||||||
|
height: 44,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: context.color.primaryContainer,
|
||||||
|
borderRadius: BorderRadius.circular(14),
|
||||||
|
),
|
||||||
|
alignment: Alignment.center,
|
||||||
|
child: IconTheme(
|
||||||
|
data: IconThemeData(
|
||||||
|
size: 20,
|
||||||
|
color: context.color.onPrimaryContainer,
|
||||||
|
),
|
||||||
|
child: feature.icon,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 14),
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
feature.title,
|
||||||
|
style: Theme.of(context).textTheme.titleSmall?.copyWith(
|
||||||
|
fontWeight: FontWeight.w700,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 3),
|
||||||
|
Text(
|
||||||
|
feature.description,
|
||||||
|
style: Theme.of(context).textTheme.bodySmall?.copyWith(
|
||||||
|
color: context.color.onSurfaceVariant,
|
||||||
|
height: 1.35,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _AdditionalChange extends StatelessWidget {
|
||||||
|
const _AdditionalChange({required this.text});
|
||||||
|
|
||||||
|
final String text;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 6),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
width: 22,
|
||||||
|
height: 22,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: context.color.primaryContainer,
|
||||||
|
shape: BoxShape.circle,
|
||||||
|
),
|
||||||
|
child: Icon(
|
||||||
|
Icons.check_rounded,
|
||||||
|
size: 15,
|
||||||
|
color: context.color.onPrimaryContainer,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 10),
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
text,
|
||||||
|
style: Theme.of(context).textTheme.bodyMedium,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
43
lib/src/visual/release_notes/release_notes_0_6_0.dart
Normal file
43
lib/src/visual/release_notes/release_notes_0_6_0.dart
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||||
|
import 'package:twonly/src/utils/misc.dart';
|
||||||
|
import 'package:twonly/src/visual/components/release_notes.comp.dart';
|
||||||
|
|
||||||
|
ReleaseNotesData releaseNotes060(BuildContext context) {
|
||||||
|
final lang = context.lang;
|
||||||
|
return ReleaseNotesData(
|
||||||
|
version: '0.6.0',
|
||||||
|
title: lang.releaseNotesTitle,
|
||||||
|
introduction: lang.releaseNotesIntroduction,
|
||||||
|
additionalChangesTitle: lang.releaseNotesAlsoImproved,
|
||||||
|
closeLabel: lang.close,
|
||||||
|
features: [
|
||||||
|
ReleaseNoteFeature(
|
||||||
|
icon: const FaIcon(FontAwesomeIcons.noteSticky),
|
||||||
|
title: lang.releaseNotesStickers,
|
||||||
|
description: lang.releaseNotesStickersDescription,
|
||||||
|
),
|
||||||
|
ReleaseNoteFeature(
|
||||||
|
icon: const FaIcon(FontAwesomeIcons.tableCellsLarge),
|
||||||
|
title: lang.releaseNotesWidgets,
|
||||||
|
description: lang.releaseNotesWidgetsDescription,
|
||||||
|
),
|
||||||
|
ReleaseNoteFeature(
|
||||||
|
icon: const FaIcon(FontAwesomeIcons.circlePlay),
|
||||||
|
title: lang.releaseNotesStories,
|
||||||
|
description: lang.releaseNotesStoriesDescription,
|
||||||
|
),
|
||||||
|
ReleaseNoteFeature(
|
||||||
|
icon: const FaIcon(FontAwesomeIcons.gamepad),
|
||||||
|
title: lang.releaseNotesMiniGames,
|
||||||
|
description: lang.releaseNotesMiniGamesDescription,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
additionalChanges: [
|
||||||
|
lang.releaseNotesReliableMessages,
|
||||||
|
lang.releaseNotesImprovedUi,
|
||||||
|
lang.releaseNotesCustomAvatars,
|
||||||
|
lang.releaseNotesArabic,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -136,6 +136,14 @@ class _ChatAskAFriendEntryState extends State<ChatAskAFriendEntry> {
|
||||||
requested: const Value(false),
|
requested: const Value(false),
|
||||||
blocked: const Value(false),
|
blocked: const Value(false),
|
||||||
deletedByUser: const Value(false),
|
deletedByUser: const Value(false),
|
||||||
|
joinedAt: userdata.joinedAt == null
|
||||||
|
? const Value.absent()
|
||||||
|
: Value(
|
||||||
|
DateTime.fromMillisecondsSinceEpoch(
|
||||||
|
userdata.joinedAt! * Duration.millisecondsPerSecond,
|
||||||
|
isUtc: true,
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
await RustApi.tryRequestContactById(
|
await RustApi.tryRequestContactById(
|
||||||
|
|
|
||||||
|
|
@ -170,6 +170,14 @@ class _ContactRowState extends State<_ContactRow> {
|
||||||
requested: const Value(false),
|
requested: const Value(false),
|
||||||
blocked: const Value(false),
|
blocked: const Value(false),
|
||||||
deletedByUser: const Value(false),
|
deletedByUser: const Value(false),
|
||||||
|
joinedAt: userdata.joinedAt == null
|
||||||
|
? const Value.absent()
|
||||||
|
: Value(
|
||||||
|
DateTime.fromMillisecondsSinceEpoch(
|
||||||
|
userdata.joinedAt! * Duration.millisecondsPerSecond,
|
||||||
|
isUtc: true,
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -158,6 +158,14 @@ class _SearchUsernameView extends State<AddNewUserView> {
|
||||||
requested: const Value(false),
|
requested: const Value(false),
|
||||||
blocked: const Value(false),
|
blocked: const Value(false),
|
||||||
deletedByUser: const Value(false),
|
deletedByUser: const Value(false),
|
||||||
|
joinedAt: userdata.joinedAt == null
|
||||||
|
? const Value.absent()
|
||||||
|
: Value(
|
||||||
|
DateTime.fromMillisecondsSinceEpoch(
|
||||||
|
userdata.joinedAt! * Duration.millisecondsPerSecond,
|
||||||
|
isUtc: true,
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -68,6 +68,14 @@ class FriendSuggestionsComp extends StatelessWidget {
|
||||||
requested: const Value(false),
|
requested: const Value(false),
|
||||||
blocked: const Value(false),
|
blocked: const Value(false),
|
||||||
deletedByUser: const Value(false),
|
deletedByUser: const Value(false),
|
||||||
|
joinedAt: userdata.joinedAt == null
|
||||||
|
? const Value.absent()
|
||||||
|
: Value(
|
||||||
|
DateTime.fromMillisecondsSinceEpoch(
|
||||||
|
userdata.joinedAt! * Duration.millisecondsPerSecond,
|
||||||
|
isUtc: true,
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -226,36 +226,64 @@ class _ContactViewState extends State<ContactView> {
|
||||||
),
|
),
|
||||||
if (getContactDisplayName(contact) != contact.username)
|
if (getContactDisplayName(contact) != contact.username)
|
||||||
Center(child: Text('(${contact.username})')),
|
Center(child: Text('(${contact.username})')),
|
||||||
if (contact.twonlyScore != null)
|
if (contact.twonlyScore != null ||
|
||||||
|
(contact.joinedAt != null && !contact.accountDeleted))
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.only(top: 10),
|
padding: const EdgeInsets.only(top: 10),
|
||||||
child: Center(
|
child: Center(
|
||||||
child: IntrinsicWidth(
|
child: Wrap(
|
||||||
child: MyChip(
|
alignment: WrapAlignment.center,
|
||||||
label: Row(
|
spacing: 8,
|
||||||
mainAxisSize: MainAxisSize.min,
|
runSpacing: 8,
|
||||||
children: [
|
children: [
|
||||||
const FaIcon(FontAwesomeIcons.trophy, size: 14),
|
if (contact.twonlyScore != null)
|
||||||
const SizedBox(width: 7),
|
IntrinsicWidth(
|
||||||
Text('${contact.twonlyScore}'),
|
child: MyChip(
|
||||||
],
|
label: Row(
|
||||||
),
|
mainAxisSize: MainAxisSize.min,
|
||||||
onTap: () => showDialog<void>(
|
children: [
|
||||||
context: context,
|
const FaIcon(FontAwesomeIcons.trophy, size: 14),
|
||||||
builder: (context) => AlertDialog(
|
const SizedBox(width: 7),
|
||||||
title: Text(context.lang.publicProfileTwonlyScore),
|
Text('${contact.twonlyScore}'),
|
||||||
content: Text(
|
],
|
||||||
context.lang.contactTwonlyScoreDescription,
|
|
||||||
),
|
|
||||||
actions: [
|
|
||||||
TextButton(
|
|
||||||
onPressed: () => Navigator.pop(context),
|
|
||||||
child: Text(context.lang.ok),
|
|
||||||
),
|
),
|
||||||
],
|
onTap: () => showDialog<void>(
|
||||||
|
context: context,
|
||||||
|
builder: (context) => AlertDialog(
|
||||||
|
title: Text(
|
||||||
|
context.lang.publicProfileTwonlyScore,
|
||||||
|
),
|
||||||
|
content: Text(
|
||||||
|
context.lang.contactTwonlyScoreDescription,
|
||||||
|
),
|
||||||
|
actions: [
|
||||||
|
TextButton(
|
||||||
|
onPressed: () => Navigator.pop(context),
|
||||||
|
child: Text(context.lang.ok),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
if (contact.joinedAt != null && !contact.accountDeleted)
|
||||||
),
|
IntrinsicWidth(
|
||||||
|
child: MyChip(
|
||||||
|
label: Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
const FaIcon(
|
||||||
|
FontAwesomeIcons.calendarDay,
|
||||||
|
size: 14,
|
||||||
|
),
|
||||||
|
const SizedBox(width: 7),
|
||||||
|
Text(formatJoinedAt(context, contact.joinedAt!)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
onTap: null,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,8 @@ import 'package:twonly/src/services/notifications/native.notifications.dart';
|
||||||
import 'package:twonly/src/services/notifications/setup.notifications.dart';
|
import 'package:twonly/src/services/notifications/setup.notifications.dart';
|
||||||
import 'package:twonly/src/utils/log.dart';
|
import 'package:twonly/src/utils/log.dart';
|
||||||
import 'package:twonly/src/utils/misc.dart';
|
import 'package:twonly/src/utils/misc.dart';
|
||||||
|
import 'package:twonly/src/visual/components/release_notes.comp.dart';
|
||||||
|
import 'package:twonly/src/visual/release_notes/release_notes_0_6_0.dart';
|
||||||
import 'package:twonly/src/visual/views/camera/camera_preview_components/camera_preview.dart';
|
import 'package:twonly/src/visual/views/camera/camera_preview_components/camera_preview.dart';
|
||||||
import 'package:twonly/src/visual/views/camera/camera_preview_components/camera_preview_controller_view.dart';
|
import 'package:twonly/src/visual/views/camera/camera_preview_components/camera_preview_controller_view.dart';
|
||||||
import 'package:twonly/src/visual/views/camera/camera_preview_components/main_camera_controller.dart';
|
import 'package:twonly/src/visual/views/camera/camera_preview_components/main_camera_controller.dart';
|
||||||
|
|
@ -45,6 +47,8 @@ class HomeViewState extends State<HomeView> with WidgetsBindingObserver {
|
||||||
/// Whether [_openEditor] has the editor open over this view.
|
/// Whether [_openEditor] has the editor open over this view.
|
||||||
bool _editorOpen = false;
|
bool _editorOpen = false;
|
||||||
bool _startPreloading = false;
|
bool _startPreloading = false;
|
||||||
|
bool _startupChecksComplete = false;
|
||||||
|
bool _releaseNotesCheckScheduled = false;
|
||||||
|
|
||||||
final MainCameraController _mainCameraController = MainCameraController();
|
final MainCameraController _mainCameraController = MainCameraController();
|
||||||
late final PageController _homeViewPageController;
|
late final PageController _homeViewPageController;
|
||||||
|
|
@ -67,6 +71,7 @@ class HomeViewState extends State<HomeView> with WidgetsBindingObserver {
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
WidgetsBinding.instance.addObserver(this);
|
WidgetsBinding.instance.addObserver(this);
|
||||||
|
routerProvider.routerDelegate.addListener(_onRouteChanged);
|
||||||
var initialPage = widget.initialPage;
|
var initialPage = widget.initialPage;
|
||||||
if (HomeViewState.pendingSharedLink != null) {
|
if (HomeViewState.pendingSharedLink != null) {
|
||||||
initialPage = 1;
|
initialPage = 1;
|
||||||
|
|
@ -97,6 +102,7 @@ class HomeViewState extends State<HomeView> with WidgetsBindingObserver {
|
||||||
if (index != 1) {
|
if (index != 1) {
|
||||||
unawaited(_mainCameraController.closeCamera());
|
unawaited(_mainCameraController.closeCamera());
|
||||||
}
|
}
|
||||||
|
_scheduleReleaseNotesIfNeeded();
|
||||||
});
|
});
|
||||||
|
|
||||||
_selectNotificationSub = selectNotificationStream.stream.listen((
|
_selectNotificationSub = selectNotificationStream.stream.listen((
|
||||||
|
|
@ -179,7 +185,12 @@ class HomeViewState extends State<HomeView> with WidgetsBindingObserver {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
unawaited(_initAsync());
|
unawaited(
|
||||||
|
_initAsync().whenComplete(() {
|
||||||
|
_startupChecksComplete = true;
|
||||||
|
_scheduleReleaseNotesIfNeeded();
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
if (_mainCameraController.sharedLinkForPreview == null &&
|
if (_mainCameraController.sharedLinkForPreview == null &&
|
||||||
|
|
@ -293,6 +304,7 @@ class HomeViewState extends State<HomeView> with WidgetsBindingObserver {
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
WidgetsBinding.instance.removeObserver(this);
|
WidgetsBinding.instance.removeObserver(this);
|
||||||
|
routerProvider.routerDelegate.removeListener(_onRouteChanged);
|
||||||
_onMessageOpenedAppSub?.cancel();
|
_onMessageOpenedAppSub?.cancel();
|
||||||
_homeViewPageIndexSub?.cancel();
|
_homeViewPageIndexSub?.cancel();
|
||||||
_selectNotificationSub?.cancel();
|
_selectNotificationSub?.cancel();
|
||||||
|
|
@ -310,10 +322,29 @@ class HomeViewState extends State<HomeView> with WidgetsBindingObserver {
|
||||||
return ModalRoute.of(context)?.isCurrent ?? false;
|
return ModalRoute.of(context)?.isCurrent ?? false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _onRouteChanged() => _scheduleReleaseNotesIfNeeded();
|
||||||
|
|
||||||
|
void _scheduleReleaseNotesIfNeeded() {
|
||||||
|
if (!_startupChecksComplete ||
|
||||||
|
_releaseNotesCheckScheduled ||
|
||||||
|
_activePageIdx != 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_releaseNotesCheckScheduled = true;
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
|
_releaseNotesCheckScheduled = false;
|
||||||
|
if (!mounted || _activePageIdx != 0 || !_isViewActive()) return;
|
||||||
|
unawaited(
|
||||||
|
ReleaseNotesPresenter.showIfNeeded(context, releaseNotes060(context)),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void didChangeAppLifecycleState(AppLifecycleState state) {
|
void didChangeAppLifecycleState(AppLifecycleState state) {
|
||||||
super.didChangeAppLifecycleState(state);
|
super.didChangeAppLifecycleState(state);
|
||||||
if (state == AppLifecycleState.resumed) {
|
if (state == AppLifecycleState.resumed) {
|
||||||
|
_scheduleReleaseNotesIfNeeded();
|
||||||
if (AppState.hasCameraPermissions &&
|
if (AppState.hasCameraPermissions &&
|
||||||
_offsetRatio < 1 &&
|
_offsetRatio < 1 &&
|
||||||
!_mainCameraController.isSharePreviewIsShown &&
|
!_mainCameraController.isSharePreviewIsShown &&
|
||||||
|
|
@ -378,6 +409,9 @@ class HomeViewState extends State<HomeView> with WidgetsBindingObserver {
|
||||||
_activePageIdx = pageIndex;
|
_activePageIdx = pageIndex;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
if (notification is ScrollEndNotification) {
|
||||||
|
_scheduleReleaseNotesIfNeeded();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (AppState.hasCameraPermissions &&
|
if (AppState.hasCameraPermissions &&
|
||||||
|
|
@ -505,7 +539,10 @@ class HomeViewState extends State<HomeView> with WidgetsBindingObserver {
|
||||||
duration: const Duration(milliseconds: 100),
|
duration: const Duration(milliseconds: 100),
|
||||||
curve: Curves.bounceIn,
|
curve: Curves.bounceIn,
|
||||||
);
|
);
|
||||||
if (mounted) setState(() {});
|
if (mounted) {
|
||||||
|
setState(() {});
|
||||||
|
_scheduleReleaseNotesIfNeeded();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
currentIndex: _activePageIdx,
|
currentIndex: _activePageIdx,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
{
|
|
||||||
"db_name": "SQLite",
|
|
||||||
"query": "UPDATE contacts SET signal_version = 'v2', account_deleted = 0 WHERE user_id = ?",
|
|
||||||
"describe": {
|
|
||||||
"columns": [],
|
|
||||||
"parameters": {
|
|
||||||
"Right": 1
|
|
||||||
},
|
|
||||||
"nullable": []
|
|
||||||
},
|
|
||||||
"hash": "7cc39bf45c3395a1f71a40d027afb0b2b7a14f18fa0ed0c66e5c9cac5678f4d4"
|
|
||||||
}
|
|
||||||
|
|
@ -332,6 +332,17 @@
|
||||||
"name": "twonly_score"
|
"name": "twonly_score"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "joined_at",
|
||||||
|
"ordinal": 30,
|
||||||
|
"type_info": "Integer",
|
||||||
|
"origin": {
|
||||||
|
"Table": {
|
||||||
|
"table": "contacts",
|
||||||
|
"name": "joined_at"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"parameters": {
|
"parameters": {
|
||||||
|
|
@ -367,6 +378,7 @@
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
|
true,
|
||||||
true
|
true
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -146,6 +146,13 @@ pub(crate) async fn handle_contact_request(
|
||||||
.build()
|
.build()
|
||||||
.insert_on_conflict_update(tr)
|
.insert_on_conflict_update(tr)
|
||||||
.await?;
|
.await?;
|
||||||
|
if let Some(joined_at) = user.joined_at {
|
||||||
|
sqlx::query("UPDATE contacts SET joined_at = ? WHERE user_id = ?")
|
||||||
|
.bind(joined_at)
|
||||||
|
.bind(from_user_id)
|
||||||
|
.execute(&mut **tr)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Type::Accept => {
|
Type::Accept => {
|
||||||
|
|
|
||||||
|
|
@ -134,6 +134,7 @@ message Response {
|
||||||
optional int64 signed_prekey_id = 6;
|
optional int64 signed_prekey_id = 6;
|
||||||
optional int64 registration_id = 8;
|
optional int64 registration_id = 8;
|
||||||
optional PqcBundle pqc_bundle = 9;
|
optional PqcBundle pqc_bundle = 9;
|
||||||
|
optional int64 joined_at = 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
message UploadToken {
|
message UploadToken {
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,39 @@ impl Server {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Loads the immutable account creation date for contacts that do not
|
||||||
|
/// already have it. Server-deleted contacts are deliberately excluded.
|
||||||
|
pub async fn refresh_contact_joined_dates(ctx: &Arc<Context>) -> Result<()> {
|
||||||
|
let database = ctx.app_db.read().await.clone();
|
||||||
|
let contact_ids = sqlx::query_scalar::<_, i64>(
|
||||||
|
"SELECT user_id FROM contacts WHERE account_deleted = 0 AND joined_at IS NULL",
|
||||||
|
)
|
||||||
|
.fetch_all(&database.pool)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
for contact_id in contact_ids {
|
||||||
|
let user = match Self::get_user_by_id(ctx, contact_id).await? {
|
||||||
|
ServerResult::Ok(user) => user,
|
||||||
|
// The shared API error handler marks UserIdNotFound contacts
|
||||||
|
// as deleted. Other per-contact errors should not prevent the
|
||||||
|
// remaining contacts from being refreshed.
|
||||||
|
ServerResult::ErrorCode(_) => continue,
|
||||||
|
};
|
||||||
|
let Some(joined_at) = user.joined_at else {
|
||||||
|
// Backwards compatibility while an older server is still
|
||||||
|
// running: leave the value NULL so a later startup retries it.
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
sqlx::query("UPDATE contacts SET joined_at = ? WHERE user_id = ?")
|
||||||
|
.bind(joined_at)
|
||||||
|
.bind(contact_id)
|
||||||
|
.execute(&database.pool)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn check_for_deleted_usernames(ctx: &Arc<Context>) -> Result<()> {
|
pub async fn check_for_deleted_usernames(ctx: &Arc<Context>) -> Result<()> {
|
||||||
let database = ctx.app_db.read().await.clone();
|
let database = ctx.app_db.read().await.clone();
|
||||||
let contacts = sqlx::query_scalar!(
|
let contacts = sqlx::query_scalar!(
|
||||||
|
|
|
||||||
|
|
@ -112,6 +112,7 @@ pub struct FrbUserData {
|
||||||
pub user_id: i64,
|
pub user_id: i64,
|
||||||
pub username: Vec<u8>,
|
pub username: Vec<u8>,
|
||||||
pub public_identity_key: Vec<u8>,
|
pub public_identity_key: Vec<u8>,
|
||||||
|
pub joined_at: Option<i64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
|
|
@ -593,8 +594,13 @@ impl RustApi {
|
||||||
user_id: res.user_id,
|
user_id: res.user_id,
|
||||||
username: res.username.unwrap_or_default(),
|
username: res.username.unwrap_or_default(),
|
||||||
public_identity_key: res.public_identity_key.unwrap_or_default(),
|
public_identity_key: res.public_identity_key.unwrap_or_default(),
|
||||||
|
joined_at: res.joined_at,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
pub async fn refresh_contact_joined_dates() -> Result<()> {
|
||||||
|
let ctx = Context::get_static()?;
|
||||||
|
Server::refresh_contact_joined_dates(ctx).await
|
||||||
|
}
|
||||||
pub async fn check_for_deleted_usernames() -> Result<()> {
|
pub async fn check_for_deleted_usernames() -> Result<()> {
|
||||||
let ctx = Context::get_static()?;
|
let ctx = Context::get_static()?;
|
||||||
Server::check_for_deleted_usernames(ctx).await
|
Server::check_for_deleted_usernames(ctx).await
|
||||||
|
|
@ -614,6 +620,7 @@ impl RustApi {
|
||||||
user_id: res.user_id,
|
user_id: res.user_id,
|
||||||
username: res.username.unwrap_or_default(),
|
username: res.username.unwrap_or_default(),
|
||||||
public_identity_key: res.public_identity_key.unwrap_or_default(),
|
public_identity_key: res.public_identity_key.unwrap_or_default(),
|
||||||
|
joined_at: res.joined_at,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
pub async fn get_proof_of_work() -> Result<FrbProofOfWork> {
|
pub async fn get_proof_of_work() -> Result<FrbProofOfWork> {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
-- UTC Unix timestamp at which the contact registered with twonly. NULL until
|
||||||
|
-- it has been loaded from a server that supports this profile field.
|
||||||
|
ALTER TABLE contacts ADD COLUMN joined_at INTEGER;
|
||||||
|
|
@ -16,7 +16,7 @@ mod legacy_import;
|
||||||
pub mod tables;
|
pub mod tables;
|
||||||
|
|
||||||
pub const APP_DATABASE_FILE: &str = "app_db.sqlite";
|
pub const APP_DATABASE_FILE: &str = "app_db.sqlite";
|
||||||
pub const APP_SCHEMA_VERSION: i64 = 14;
|
pub const APP_SCHEMA_VERSION: i64 = 15;
|
||||||
|
|
||||||
/// User-owned application tables in the current Rust schema. Rust-only outbox
|
/// User-owned application tables in the current Rust schema. Rust-only outbox
|
||||||
/// tables are deliberately absent because they are reconstructed locally.
|
/// tables are deliberately absent because they are reconstructed locally.
|
||||||
|
|
@ -402,6 +402,34 @@ mod change_notification_tests {
|
||||||
(directory, database)
|
(directory, database)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn contact_joined_at_is_nullable_and_persisted() {
|
||||||
|
let (_dir, database) = open().await;
|
||||||
|
sqlx::query("INSERT INTO contacts(user_id, username) VALUES(7, 'alice')")
|
||||||
|
.execute(&database.pool)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let joined_at: Option<i64> =
|
||||||
|
sqlx::query_scalar("SELECT joined_at FROM contacts WHERE user_id = 7")
|
||||||
|
.fetch_one(&database.pool)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(joined_at, None);
|
||||||
|
|
||||||
|
sqlx::query("UPDATE contacts SET joined_at = ? WHERE user_id = 7")
|
||||||
|
.bind(1_700_000_000_i64)
|
||||||
|
.execute(&database.pool)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
let joined_at: Option<i64> =
|
||||||
|
sqlx::query_scalar("SELECT joined_at FROM contacts WHERE user_id = 7")
|
||||||
|
.fetch_one(&database.pool)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(joined_at, Some(1_700_000_000));
|
||||||
|
}
|
||||||
|
|
||||||
fn insert(key: &str) -> String {
|
fn insert(key: &str) -> String {
|
||||||
format!("INSERT INTO app_metadata(key, value) VALUES('{key}', '1')")
|
format!("INSERT INTO app_metadata(key, value) VALUES('{key}', '1')")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,7 @@ pub struct Contact {
|
||||||
pub widget_sharing_allowed: i64,
|
pub widget_sharing_allowed: i64,
|
||||||
pub widget_sharing_granted: i64,
|
pub widget_sharing_granted: i64,
|
||||||
pub twonly_score: Option<i64>,
|
pub twonly_score: Option<i64>,
|
||||||
|
pub joined_at: Option<i64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(bon::Builder)]
|
#[derive(bon::Builder)]
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ flutter_rust_bridge::frb_generated_boilerplate!(
|
||||||
default_rust_auto_opaque = RustAutoOpaqueMoi,
|
default_rust_auto_opaque = RustAutoOpaqueMoi,
|
||||||
);
|
);
|
||||||
pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_VERSION: &str = "2.12.0";
|
pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_VERSION: &str = "2.12.0";
|
||||||
pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_CONTENT_HASH: i32 = -1844664049;
|
pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_CONTENT_HASH: i32 = -1901082359;
|
||||||
|
|
||||||
// Section: executor
|
// Section: executor
|
||||||
|
|
||||||
|
|
@ -3479,6 +3479,42 @@ fn wire__crate__bridge__api__rust_api_purge_widget_media_impl(
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
fn wire__crate__bridge__api__rust_api_refresh_contact_joined_dates_impl(
|
||||||
|
port_: flutter_rust_bridge::for_generated::MessagePort,
|
||||||
|
ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr,
|
||||||
|
rust_vec_len_: i32,
|
||||||
|
data_len_: i32,
|
||||||
|
) {
|
||||||
|
FLUTTER_RUST_BRIDGE_HANDLER.wrap_async::<flutter_rust_bridge::for_generated::SseCodec, _, _, _>(
|
||||||
|
flutter_rust_bridge::for_generated::TaskInfo {
|
||||||
|
debug_name: "rust_api_refresh_contact_joined_dates",
|
||||||
|
port: Some(port_),
|
||||||
|
mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal,
|
||||||
|
},
|
||||||
|
move || {
|
||||||
|
let message = unsafe {
|
||||||
|
flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire(
|
||||||
|
ptr_,
|
||||||
|
rust_vec_len_,
|
||||||
|
data_len_,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
let mut deserializer =
|
||||||
|
flutter_rust_bridge::for_generated::SseDeserializer::new(message);
|
||||||
|
deserializer.end();
|
||||||
|
move |context| async move {
|
||||||
|
transform_result_sse::<_, flutter_rust_bridge::for_generated::anyhow::Error>(
|
||||||
|
(move || async move {
|
||||||
|
let output_ok =
|
||||||
|
crate::bridge::api::RustApi::refresh_contact_joined_dates().await?;
|
||||||
|
Ok(output_ok)
|
||||||
|
})()
|
||||||
|
.await,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
fn wire__crate__bridge__api__rust_api_refresh_widget_manifest_impl(
|
fn wire__crate__bridge__api__rust_api_refresh_widget_manifest_impl(
|
||||||
port_: flutter_rust_bridge::for_generated::MessagePort,
|
port_: flutter_rust_bridge::for_generated::MessagePort,
|
||||||
ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr,
|
ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr,
|
||||||
|
|
@ -7055,10 +7091,12 @@ impl SseDecode for crate::bridge::api::FrbUserData {
|
||||||
let mut var_userId = <i64>::sse_decode(deserializer);
|
let mut var_userId = <i64>::sse_decode(deserializer);
|
||||||
let mut var_username = <Vec<u8>>::sse_decode(deserializer);
|
let mut var_username = <Vec<u8>>::sse_decode(deserializer);
|
||||||
let mut var_publicIdentityKey = <Vec<u8>>::sse_decode(deserializer);
|
let mut var_publicIdentityKey = <Vec<u8>>::sse_decode(deserializer);
|
||||||
|
let mut var_joinedAt = <Option<i64>>::sse_decode(deserializer);
|
||||||
return crate::bridge::api::FrbUserData {
|
return crate::bridge::api::FrbUserData {
|
||||||
user_id: var_userId,
|
user_id: var_userId,
|
||||||
username: var_username,
|
username: var_username,
|
||||||
public_identity_key: var_publicIdentityKey,
|
public_identity_key: var_publicIdentityKey,
|
||||||
|
joined_at: var_joinedAt,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -7944,6 +7982,7 @@ impl SseDecode for crate::user_config::UserConfig {
|
||||||
let mut var_currentSignedPreKeyIndexStart = <i64>::sse_decode(deserializer);
|
let mut var_currentSignedPreKeyIndexStart = <i64>::sse_decode(deserializer);
|
||||||
let mut var_lastChangeLogHash = <Option<Vec<u8>>>::sse_decode(deserializer);
|
let mut var_lastChangeLogHash = <Option<Vec<u8>>>::sse_decode(deserializer);
|
||||||
let mut var_hideChangeLog = <bool>::sse_decode(deserializer);
|
let mut var_hideChangeLog = <bool>::sse_decode(deserializer);
|
||||||
|
let mut var_lastReleaseNotesVersion = <Option<String>>::sse_decode(deserializer);
|
||||||
let mut var_hideMemoriesBackupPromo = <bool>::sse_decode(deserializer);
|
let mut var_hideMemoriesBackupPromo = <bool>::sse_decode(deserializer);
|
||||||
let mut var_hideWidgetShareExplainer = <bool>::sse_decode(deserializer);
|
let mut var_hideWidgetShareExplainer = <bool>::sse_decode(deserializer);
|
||||||
let mut var_updateFcmToken = <bool>::sse_decode(deserializer);
|
let mut var_updateFcmToken = <bool>::sse_decode(deserializer);
|
||||||
|
|
@ -8013,6 +8052,7 @@ impl SseDecode for crate::user_config::UserConfig {
|
||||||
current_signed_pre_key_index_start: var_currentSignedPreKeyIndexStart,
|
current_signed_pre_key_index_start: var_currentSignedPreKeyIndexStart,
|
||||||
last_change_log_hash: var_lastChangeLogHash,
|
last_change_log_hash: var_lastChangeLogHash,
|
||||||
hide_change_log: var_hideChangeLog,
|
hide_change_log: var_hideChangeLog,
|
||||||
|
last_release_notes_version: var_lastReleaseNotesVersion,
|
||||||
hide_memories_backup_promo: var_hideMemoriesBackupPromo,
|
hide_memories_backup_promo: var_hideMemoriesBackupPromo,
|
||||||
hide_widget_share_explainer: var_hideWidgetShareExplainer,
|
hide_widget_share_explainer: var_hideWidgetShareExplainer,
|
||||||
update_fcm_token: var_updateFcmToken,
|
update_fcm_token: var_updateFcmToken,
|
||||||
|
|
@ -8246,92 +8286,93 @@ fn pde_ffi_dispatcher_primary_impl(
|
||||||
91 => wire__crate__bridge__api__rust_api_prewarm_memory_location_impl(port, ptr, rust_vec_len, data_len),
|
91 => wire__crate__bridge__api__rust_api_prewarm_memory_location_impl(port, ptr, rust_vec_len, data_len),
|
||||||
92 => wire__crate__bridge__api__rust_api_purge_media_temp_folder_impl(port, ptr, rust_vec_len, data_len),
|
92 => wire__crate__bridge__api__rust_api_purge_media_temp_folder_impl(port, ptr, rust_vec_len, data_len),
|
||||||
93 => wire__crate__bridge__api__rust_api_purge_widget_media_impl(port, ptr, rust_vec_len, data_len),
|
93 => wire__crate__bridge__api__rust_api_purge_widget_media_impl(port, ptr, rust_vec_len, data_len),
|
||||||
94 => wire__crate__bridge__api__rust_api_refresh_widget_manifest_impl(port, ptr, rust_vec_len, data_len),
|
94 => wire__crate__bridge__api__rust_api_refresh_contact_joined_dates_impl(port, ptr, rust_vec_len, data_len),
|
||||||
95 => wire__crate__bridge__api__rust_api_register_impl(port, ptr, rust_vec_len, data_len),
|
95 => wire__crate__bridge__api__rust_api_refresh_widget_manifest_impl(port, ptr, rust_vec_len, data_len),
|
||||||
96 => wire__crate__bridge__api__rust_api_register_home_widget_impl(port, ptr, rust_vec_len, data_len),
|
96 => wire__crate__bridge__api__rust_api_register_impl(port, ptr, rust_vec_len, data_len),
|
||||||
97 => wire__crate__bridge__api__rust_api_register_passwordless_notification_impl(port, ptr, rust_vec_len, data_len),
|
97 => wire__crate__bridge__api__rust_api_register_home_widget_impl(port, ptr, rust_vec_len, data_len),
|
||||||
98 => wire__crate__bridge__api__rust_api_register_passwordless_recovery_impl(port, ptr, rust_vec_len, data_len),
|
98 => wire__crate__bridge__api__rust_api_register_passwordless_notification_impl(port, ptr, rust_vec_len, data_len),
|
||||||
99 => wire__crate__bridge__api__rust_api_reload_configuration_impl(port, ptr, rust_vec_len, data_len),
|
99 => wire__crate__bridge__api__rust_api_register_passwordless_recovery_impl(port, ptr, rust_vec_len, data_len),
|
||||||
100 => wire__crate__bridge__api__rust_api_remove_additional_user_impl(port, ptr, rust_vec_len, data_len),
|
100 => wire__crate__bridge__api__rust_api_reload_configuration_impl(port, ptr, rust_vec_len, data_len),
|
||||||
101 => wire__crate__bridge__api__rust_api_remove_media_files_impl(port, ptr, rust_vec_len, data_len),
|
101 => wire__crate__bridge__api__rust_api_remove_additional_user_impl(port, ptr, rust_vec_len, data_len),
|
||||||
102 => wire__crate__bridge__api__rust_api_report_user_impl(port, ptr, rust_vec_len, data_len),
|
102 => wire__crate__bridge__api__rust_api_remove_media_files_impl(port, ptr, rust_vec_len, data_len),
|
||||||
103 => wire__crate__bridge__api__rust_api_request_binary_impl(port, ptr, rust_vec_len, data_len),
|
103 => wire__crate__bridge__api__rust_api_report_user_impl(port, ptr, rust_vec_len, data_len),
|
||||||
104 => wire__crate__bridge__api__rust_api_request_contact_by_username_impl(port, ptr, rust_vec_len, data_len),
|
104 => wire__crate__bridge__api__rust_api_request_binary_impl(port, ptr, rust_vec_len, data_len),
|
||||||
105 => wire__crate__bridge__api__rust_api_request_media_reupload_impl(port, ptr, rust_vec_len, data_len),
|
105 => wire__crate__bridge__api__rust_api_request_contact_by_username_impl(port, ptr, rust_vec_len, data_len),
|
||||||
106 => wire__crate__bridge__api__rust_api_request_memories_upload_impl(port, ptr, rust_vec_len, data_len),
|
106 => wire__crate__bridge__api__rust_api_request_media_reupload_impl(port, ptr, rust_vec_len, data_len),
|
||||||
107 => wire__crate__bridge__api__rust_api_retransmit_all_messages_impl(port, ptr, rust_vec_len, data_len),
|
107 => wire__crate__bridge__api__rust_api_request_memories_upload_impl(port, ptr, rust_vec_len, data_len),
|
||||||
108 => wire__crate__bridge__api__rust_api_retry_pending_media_reuploads_impl(port, ptr, rust_vec_len, data_len),
|
108 => wire__crate__bridge__api__rust_api_retransmit_all_messages_impl(port, ptr, rust_vec_len, data_len),
|
||||||
109 => wire__crate__bridge__api__rust_api_reupload_pending_media_impl(port, ptr, rust_vec_len, data_len),
|
109 => wire__crate__bridge__api__rust_api_retry_pending_media_reuploads_impl(port, ptr, rust_vec_len, data_len),
|
||||||
110 => wire__crate__bridge__api__rust_api_save_media_to_gallery_impl(port, ptr, rust_vec_len, data_len),
|
110 => wire__crate__bridge__api__rust_api_reupload_pending_media_impl(port, ptr, rust_vec_len, data_len),
|
||||||
111 => wire__crate__bridge__api__rust_api_send_binary_impl(port, ptr, rust_vec_len, data_len),
|
111 => wire__crate__bridge__api__rust_api_save_media_to_gallery_impl(port, ptr, rust_vec_len, data_len),
|
||||||
112 => wire__crate__bridge__api__rust_api_send_contact_profile_impl(port, ptr, rust_vec_len, data_len),
|
112 => wire__crate__bridge__api__rust_api_send_binary_impl(port, ptr, rust_vec_len, data_len),
|
||||||
113 => wire__crate__bridge__api__rust_api_send_encrypted_content_impl(port, ptr, rust_vec_len, data_len),
|
113 => wire__crate__bridge__api__rust_api_send_contact_profile_impl(port, ptr, rust_vec_len, data_len),
|
||||||
114 => wire__crate__bridge__api__rust_api_send_encrypted_content_to_group_impl(port, ptr, rust_vec_len, data_len),
|
114 => wire__crate__bridge__api__rust_api_send_encrypted_content_impl(port, ptr, rust_vec_len, data_len),
|
||||||
115 => wire__crate__bridge__api__rust_api_send_media_to_groups_impl(port, ptr, rust_vec_len, data_len),
|
115 => wire__crate__bridge__api__rust_api_send_encrypted_content_to_group_impl(port, ptr, rust_vec_len, data_len),
|
||||||
116 => wire__crate__bridge__api__rust_api_send_queued_message_impl(port, ptr, rust_vec_len, data_len),
|
116 => wire__crate__bridge__api__rust_api_send_media_to_groups_impl(port, ptr, rust_vec_len, data_len),
|
||||||
117 => wire__crate__bridge__api__rust_api_send_text_message_impl(port, ptr, rust_vec_len, data_len),
|
117 => wire__crate__bridge__api__rust_api_send_queued_message_impl(port, ptr, rust_vec_len, data_len),
|
||||||
118 => wire__crate__bridge__api__rust_api_send_typing_impl(port, ptr, rust_vec_len, data_len),
|
118 => wire__crate__bridge__api__rust_api_send_text_message_impl(port, ptr, rust_vec_len, data_len),
|
||||||
119 => wire__crate__bridge__api__rust_api_set_background_impl(port, ptr, rust_vec_len, data_len),
|
119 => wire__crate__bridge__api__rust_api_send_typing_impl(port, ptr, rust_vec_len, data_len),
|
||||||
120 => wire__crate__bridge__api__rust_api_set_home_widget_groups_impl(port, ptr, rust_vec_len, data_len),
|
120 => wire__crate__bridge__api__rust_api_set_background_impl(port, ptr, rust_vec_len, data_len),
|
||||||
121 => wire__crate__bridge__api__rust_api_set_login_token_impl(port, ptr, rust_vec_len, data_len),
|
121 => wire__crate__bridge__api__rust_api_set_home_widget_groups_impl(port, ptr, rust_vec_len, data_len),
|
||||||
122 => wire__crate__bridge__api__rust_api_set_media_display_limit_impl(port, ptr, rust_vec_len, data_len),
|
122 => wire__crate__bridge__api__rust_api_set_login_token_impl(port, ptr, rust_vec_len, data_len),
|
||||||
123 => wire__crate__bridge__api__rust_api_set_media_requires_authentication_impl(port, ptr, rust_vec_len, data_len),
|
123 => wire__crate__bridge__api__rust_api_set_media_display_limit_impl(port, ptr, rust_vec_len, data_len),
|
||||||
124 => wire__crate__bridge__api__rust_api_set_media_trim_impl(port, ptr, rust_vec_len, data_len),
|
124 => wire__crate__bridge__api__rust_api_set_media_requires_authentication_impl(port, ptr, rust_vec_len, data_len),
|
||||||
125 => wire__crate__bridge__api__rust_api_set_network_available_impl(port, ptr, rust_vec_len, data_len),
|
125 => wire__crate__bridge__api__rust_api_set_media_trim_impl(port, ptr, rust_vec_len, data_len),
|
||||||
126 => wire__crate__bridge__api__rust_api_store_media_impl(port, ptr, rust_vec_len, data_len),
|
126 => wire__crate__bridge__api__rust_api_set_network_available_impl(port, ptr, rust_vec_len, data_len),
|
||||||
127 => wire__crate__bridge__api__rust_api_submit_recovery_share_impl(port, ptr, rust_vec_len, data_len),
|
127 => wire__crate__bridge__api__rust_api_store_media_impl(port, ptr, rust_vec_len, data_len),
|
||||||
128 => wire__crate__bridge__api__rust_api_sync_widget_permissions_impl(port, ptr, rust_vec_len, data_len),
|
128 => wire__crate__bridge__api__rust_api_submit_recovery_share_impl(port, ptr, rust_vec_len, data_len),
|
||||||
129 => wire__crate__bridge__api__rust_api_toggle_media_remove_audio_impl(port, ptr, rust_vec_len, data_len),
|
129 => wire__crate__bridge__api__rust_api_sync_widget_permissions_impl(port, ptr, rust_vec_len, data_len),
|
||||||
130 => wire__crate__bridge__api__rust_api_try_request_contact_by_id_impl(port, ptr, rust_vec_len, data_len),
|
130 => wire__crate__bridge__api__rust_api_toggle_media_remove_audio_impl(port, ptr, rust_vec_len, data_len),
|
||||||
131 => wire__crate__bridge__api__rust_api_unregister_home_widget_impl(port, ptr, rust_vec_len, data_len),
|
131 => wire__crate__bridge__api__rust_api_try_request_contact_by_id_impl(port, ptr, rust_vec_len, data_len),
|
||||||
132 => wire__crate__bridge__api__rust_api_update_fcm_token_impl(port, ptr, rust_vec_len, data_len),
|
132 => wire__crate__bridge__api__rust_api_unregister_home_widget_impl(port, ptr, rust_vec_len, data_len),
|
||||||
133 => wire__crate__bridge__api__rust_api_update_signed_pre_key_impl(port, ptr, rust_vec_len, data_len),
|
133 => wire__crate__bridge__api__rust_api_update_fcm_token_impl(port, ptr, rust_vec_len, data_len),
|
||||||
134 => wire__crate__bridge__api__rust_api_upload_pqc_pre_keys_impl(port, ptr, rust_vec_len, data_len),
|
134 => wire__crate__bridge__api__rust_api_update_signed_pre_key_impl(port, ptr, rust_vec_len, data_len),
|
||||||
135 => wire__crate__bridge__wrapper__app_database__rust_app_database_changes_impl(port, ptr, rust_vec_len, data_len),
|
135 => wire__crate__bridge__api__rust_api_upload_pqc_pre_keys_impl(port, ptr, rust_vec_len, data_len),
|
||||||
136 => wire__crate__bridge__wrapper__app_database__rust_app_database_execute_impl(port, ptr, rust_vec_len, data_len),
|
136 => wire__crate__bridge__wrapper__app_database__rust_app_database_changes_impl(port, ptr, rust_vec_len, data_len),
|
||||||
137 => wire__crate__bridge__wrapper__app_database__rust_app_database_legacy_import_complete_impl(port, ptr, rust_vec_len, data_len),
|
137 => wire__crate__bridge__wrapper__app_database__rust_app_database_execute_impl(port, ptr, rust_vec_len, data_len),
|
||||||
138 => wire__crate__bridge__wrapper__app_database__rust_app_database_migrate_legacy_database_impl(port, ptr, rust_vec_len, data_len),
|
138 => wire__crate__bridge__wrapper__app_database__rust_app_database_legacy_import_complete_impl(port, ptr, rust_vec_len, data_len),
|
||||||
139 => wire__crate__bridge__wrapper__app_database__rust_app_database_select_impl(port, ptr, rust_vec_len, data_len),
|
139 => wire__crate__bridge__wrapper__app_database__rust_app_database_migrate_legacy_database_impl(port, ptr, rust_vec_len, data_len),
|
||||||
140 => wire__crate__bridge__wrapper__backup__rust_backup_archive_create_backup_archive_impl(port, ptr, rust_vec_len, data_len),
|
140 => wire__crate__bridge__wrapper__app_database__rust_app_database_select_impl(port, ptr, rust_vec_len, data_len),
|
||||||
141 => wire__crate__bridge__wrapper__backup__rust_backup_archive_get_backup_download_token_impl(port, ptr, rust_vec_len, data_len),
|
141 => wire__crate__bridge__wrapper__backup__rust_backup_archive_create_backup_archive_impl(port, ptr, rust_vec_len, data_len),
|
||||||
142 => wire__crate__bridge__wrapper__backup__rust_backup_archive_restore_backup_archive_impl(port, ptr, rust_vec_len, data_len),
|
142 => wire__crate__bridge__wrapper__backup__rust_backup_archive_get_backup_download_token_impl(port, ptr, rust_vec_len, data_len),
|
||||||
143 => wire__crate__bridge__wrapper__backup__rust_backup_identity_get_backup_id_impl(port, ptr, rust_vec_len, data_len),
|
143 => wire__crate__bridge__wrapper__backup__rust_backup_archive_restore_backup_archive_impl(port, ptr, rust_vec_len, data_len),
|
||||||
144 => wire__crate__bridge__wrapper__backup__rust_backup_identity_get_backup_password_keys_impl(port, ptr, rust_vec_len, data_len),
|
144 => wire__crate__bridge__wrapper__backup__rust_backup_identity_get_backup_id_impl(port, ptr, rust_vec_len, data_len),
|
||||||
145 => wire__crate__bridge__wrapper__backup__rust_backup_identity_get_identity_backup_bytes_impl(port, ptr, rust_vec_len, data_len),
|
145 => wire__crate__bridge__wrapper__backup__rust_backup_identity_get_backup_password_keys_impl(port, ptr, rust_vec_len, data_len),
|
||||||
146 => wire__crate__bridge__wrapper__backup__rust_backup_identity_import_backup_password_keys_impl(port, ptr, rust_vec_len, data_len),
|
146 => wire__crate__bridge__wrapper__backup__rust_backup_identity_get_identity_backup_bytes_impl(port, ptr, rust_vec_len, data_len),
|
||||||
147 => wire__crate__bridge__wrapper__backup__rust_backup_identity_restore_identity_backup_impl(port, ptr, rust_vec_len, data_len),
|
147 => wire__crate__bridge__wrapper__backup__rust_backup_identity_import_backup_password_keys_impl(port, ptr, rust_vec_len, data_len),
|
||||||
148 => wire__crate__bridge__wrapper__backup__rust_backup_identity_set_backup_password_keys_impl(port, ptr, rust_vec_len, data_len),
|
148 => wire__crate__bridge__wrapper__backup__rust_backup_identity_restore_identity_backup_impl(port, ptr, rust_vec_len, data_len),
|
||||||
149 => wire__crate__bridge__wrapper__key_manager__rust_key_manager_decrypt_cloud_media_key_impl(port, ptr, rust_vec_len, data_len),
|
149 => wire__crate__bridge__wrapper__backup__rust_backup_identity_set_backup_password_keys_impl(port, ptr, rust_vec_len, data_len),
|
||||||
150 => wire__crate__bridge__wrapper__key_manager__rust_key_manager_encrypt_cloud_media_key_impl(port, ptr, rust_vec_len, data_len),
|
150 => wire__crate__bridge__wrapper__key_manager__rust_key_manager_decrypt_cloud_media_key_impl(port, ptr, rust_vec_len, data_len),
|
||||||
151 => wire__crate__bridge__wrapper__key_manager__rust_key_manager_get_signal_identity_impl(port, ptr, rust_vec_len, data_len),
|
151 => wire__crate__bridge__wrapper__key_manager__rust_key_manager_encrypt_cloud_media_key_impl(port, ptr, rust_vec_len, data_len),
|
||||||
152 => wire__crate__bridge__wrapper__key_manager__rust_key_manager_get_user_id_impl(port, ptr, rust_vec_len, data_len),
|
152 => wire__crate__bridge__wrapper__key_manager__rust_key_manager_get_signal_identity_impl(port, ptr, rust_vec_len, data_len),
|
||||||
153 => wire__crate__bridge__wrapper__key_manager__rust_key_manager_import_serialized_impl(port, ptr, rust_vec_len, data_len),
|
153 => wire__crate__bridge__wrapper__key_manager__rust_key_manager_get_user_id_impl(port, ptr, rust_vec_len, data_len),
|
||||||
154 => wire__crate__bridge__wrapper__key_manager__rust_key_manager_import_signal_identity_impl(port, ptr, rust_vec_len, data_len),
|
154 => wire__crate__bridge__wrapper__key_manager__rust_key_manager_import_serialized_impl(port, ptr, rust_vec_len, data_len),
|
||||||
155 => wire__crate__bridge__wrapper__key_manager__rust_key_manager_remove_local_credentials_impl(port, ptr, rust_vec_len, data_len),
|
155 => wire__crate__bridge__wrapper__key_manager__rust_key_manager_import_signal_identity_impl(port, ptr, rust_vec_len, data_len),
|
||||||
156 => wire__crate__bridge__wrapper__key_manager__rust_key_manager_serialize_impl(port, ptr, rust_vec_len, data_len),
|
156 => wire__crate__bridge__wrapper__key_manager__rust_key_manager_remove_local_credentials_impl(port, ptr, rust_vec_len, data_len),
|
||||||
157 => wire__crate__bridge__wrapper__key_manager__rust_key_manager_set_user_id_impl(port, ptr, rust_vec_len, data_len),
|
157 => wire__crate__bridge__wrapper__key_manager__rust_key_manager_serialize_impl(port, ptr, rust_vec_len, data_len),
|
||||||
158 => wire__crate__bridge__wrapper__signal__rust_signal_decrypt_impl(port, ptr, rust_vec_len, data_len),
|
158 => wire__crate__bridge__wrapper__key_manager__rust_key_manager_set_user_id_impl(port, ptr, rust_vec_len, data_len),
|
||||||
159 => wire__crate__bridge__wrapper__signal__rust_signal_encrypt_impl(port, ptr, rust_vec_len, data_len),
|
159 => wire__crate__bridge__wrapper__signal__rust_signal_decrypt_impl(port, ptr, rust_vec_len, data_len),
|
||||||
160 => wire__crate__bridge__wrapper__signal__rust_signal_generate_bundle_impl(port, ptr, rust_vec_len, data_len),
|
160 => wire__crate__bridge__wrapper__signal__rust_signal_encrypt_impl(port, ptr, rust_vec_len, data_len),
|
||||||
161 => wire__crate__bridge__wrapper__signal__rust_signal_generate_pqc_prekeys_impl(port, ptr, rust_vec_len, data_len),
|
161 => wire__crate__bridge__wrapper__signal__rust_signal_generate_bundle_impl(port, ptr, rust_vec_len, data_len),
|
||||||
162 => wire__crate__bridge__wrapper__signal__rust_signal_get_contact_public_key_impl(port, ptr, rust_vec_len, data_len),
|
162 => wire__crate__bridge__wrapper__signal__rust_signal_generate_pqc_prekeys_impl(port, ptr, rust_vec_len, data_len),
|
||||||
163 => wire__crate__bridge__wrapper__signal__rust_signal_get_safety_number_impl(port, ptr, rust_vec_len, data_len),
|
163 => wire__crate__bridge__wrapper__signal__rust_signal_get_contact_public_key_impl(port, ptr, rust_vec_len, data_len),
|
||||||
164 => wire__crate__bridge__wrapper__signal__rust_signal_get_user_public_key_impl(port, ptr, rust_vec_len, data_len),
|
164 => wire__crate__bridge__wrapper__signal__rust_signal_get_safety_number_impl(port, ptr, rust_vec_len, data_len),
|
||||||
165 => wire__crate__bridge__wrapper__signal__rust_signal_process_prekey_bundle_impl(port, ptr, rust_vec_len, data_len),
|
165 => wire__crate__bridge__wrapper__signal__rust_signal_get_user_public_key_impl(port, ptr, rust_vec_len, data_len),
|
||||||
166 => wire__crate__bridge__wrapper__signal__rust_signal_reset_contact_session_impl(port, ptr, rust_vec_len, data_len),
|
166 => wire__crate__bridge__wrapper__signal__rust_signal_process_prekey_bundle_impl(port, ptr, rust_vec_len, data_len),
|
||||||
167 => wire__crate__bridge__wrapper__rust_utils_generate_shares_impl(port, ptr, rust_vec_len, data_len),
|
167 => wire__crate__bridge__wrapper__signal__rust_signal_reset_contact_session_impl(port, ptr, rust_vec_len, data_len),
|
||||||
168 => wire__crate__bridge__wrapper__rust_utils_recover_secret_impl(port, ptr, rust_vec_len, data_len),
|
168 => wire__crate__bridge__wrapper__rust_utils_generate_shares_impl(port, ptr, rust_vec_len, data_len),
|
||||||
169 => wire__crate__bridge__webxdc__send_update_impl(port, ptr, rust_vec_len, data_len),
|
169 => wire__crate__bridge__wrapper__rust_utils_recover_secret_impl(port, ptr, rust_vec_len, data_len),
|
||||||
170 => wire__crate__bridge__webxdc__serve_impl(port, ptr, rust_vec_len, data_len),
|
170 => wire__crate__bridge__webxdc__send_update_impl(port, ptr, rust_vec_len, data_len),
|
||||||
171 => wire__crate__bridge__stories__story_audience_chats_impl(port, ptr, rust_vec_len, data_len),
|
171 => wire__crate__bridge__webxdc__serve_impl(port, ptr, rust_vec_len, data_len),
|
||||||
172 => wire__crate__bridge__groups__update_chat_deletion_time_impl(port, ptr, rust_vec_len, data_len),
|
172 => wire__crate__bridge__stories__story_audience_chats_impl(port, ptr, rust_vec_len, data_len),
|
||||||
173 => wire__crate__bridge__groups__update_group_name_impl(port, ptr, rust_vec_len, data_len),
|
173 => wire__crate__bridge__groups__update_chat_deletion_time_impl(port, ptr, rust_vec_len, data_len),
|
||||||
174 => wire__crate__bridge__webxdc__updates_after_impl(port, ptr, rust_vec_len, data_len),
|
174 => wire__crate__bridge__groups__update_group_name_impl(port, ptr, rust_vec_len, data_len),
|
||||||
176 => wire__crate__bridge__user_config__user_config_api_create_impl(port, ptr, rust_vec_len, data_len),
|
175 => wire__crate__bridge__webxdc__updates_after_impl(port, ptr, rust_vec_len, data_len),
|
||||||
177 => wire__crate__bridge__user_config__user_config_api_import_json_impl(port, ptr, rust_vec_len, data_len),
|
177 => wire__crate__bridge__user_config__user_config_api_create_impl(port, ptr, rust_vec_len, data_len),
|
||||||
178 => wire__crate__bridge__user_config__user_config_api_load_impl(port, ptr, rust_vec_len, data_len),
|
178 => wire__crate__bridge__user_config__user_config_api_import_json_impl(port, ptr, rust_vec_len, data_len),
|
||||||
179 => wire__crate__bridge__user_config__user_config_api_save_impl(port, ptr, rust_vec_len, data_len),
|
179 => wire__crate__bridge__user_config__user_config_api_load_impl(port, ptr, rust_vec_len, data_len),
|
||||||
180 => wire__crate__bridge__user_config__user_config_api_update_impl(port, ptr, rust_vec_len, data_len),
|
180 => wire__crate__bridge__user_config__user_config_api_save_impl(port, ptr, rust_vec_len, data_len),
|
||||||
|
181 => wire__crate__bridge__user_config__user_config_api_update_impl(port, ptr, rust_vec_len, data_len),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -8350,12 +8391,12 @@ fn pde_ffi_dispatcher_sync_impl(
|
||||||
55 => {
|
55 => {
|
||||||
wire__crate__bridge__api__rust_api_decode_avatar_svg_impl(ptr, rust_vec_len, data_len)
|
wire__crate__bridge__api__rust_api_decode_avatar_svg_impl(ptr, rust_vec_len, data_len)
|
||||||
}
|
}
|
||||||
175 => wire__crate__bridge__user_config__user_config_api_clone_impl(
|
176 => wire__crate__bridge__user_config__user_config_api_clone_impl(
|
||||||
ptr,
|
ptr,
|
||||||
rust_vec_len,
|
rust_vec_len,
|
||||||
data_len,
|
data_len,
|
||||||
),
|
),
|
||||||
181 => wire__crate__bridge__logging__write_log_impl(ptr, rust_vec_len, data_len),
|
182 => wire__crate__bridge__logging__write_log_impl(ptr, rust_vec_len, data_len),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -8720,6 +8761,7 @@ impl flutter_rust_bridge::IntoDart for crate::bridge::api::FrbUserData {
|
||||||
self.user_id.into_into_dart().into_dart(),
|
self.user_id.into_into_dart().into_dart(),
|
||||||
self.username.into_into_dart().into_dart(),
|
self.username.into_into_dart().into_dart(),
|
||||||
self.public_identity_key.into_into_dart().into_dart(),
|
self.public_identity_key.into_into_dart().into_dart(),
|
||||||
|
self.joined_at.into_into_dart().into_dart(),
|
||||||
]
|
]
|
||||||
.into_dart()
|
.into_dart()
|
||||||
}
|
}
|
||||||
|
|
@ -9321,6 +9363,7 @@ impl flutter_rust_bridge::IntoDart for crate::user_config::UserConfig {
|
||||||
.into_dart(),
|
.into_dart(),
|
||||||
self.last_change_log_hash.into_into_dart().into_dart(),
|
self.last_change_log_hash.into_into_dart().into_dart(),
|
||||||
self.hide_change_log.into_into_dart().into_dart(),
|
self.hide_change_log.into_into_dart().into_dart(),
|
||||||
|
self.last_release_notes_version.into_into_dart().into_dart(),
|
||||||
self.hide_memories_backup_promo.into_into_dart().into_dart(),
|
self.hide_memories_backup_promo.into_into_dart().into_dart(),
|
||||||
self.hide_widget_share_explainer
|
self.hide_widget_share_explainer
|
||||||
.into_into_dart()
|
.into_into_dart()
|
||||||
|
|
@ -9758,6 +9801,7 @@ impl SseEncode for crate::bridge::api::FrbUserData {
|
||||||
<i64>::sse_encode(self.user_id, serializer);
|
<i64>::sse_encode(self.user_id, serializer);
|
||||||
<Vec<u8>>::sse_encode(self.username, serializer);
|
<Vec<u8>>::sse_encode(self.username, serializer);
|
||||||
<Vec<u8>>::sse_encode(self.public_identity_key, serializer);
|
<Vec<u8>>::sse_encode(self.public_identity_key, serializer);
|
||||||
|
<Option<i64>>::sse_encode(self.joined_at, serializer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -10516,6 +10560,7 @@ impl SseEncode for crate::user_config::UserConfig {
|
||||||
<i64>::sse_encode(self.current_signed_pre_key_index_start, serializer);
|
<i64>::sse_encode(self.current_signed_pre_key_index_start, serializer);
|
||||||
<Option<Vec<u8>>>::sse_encode(self.last_change_log_hash, serializer);
|
<Option<Vec<u8>>>::sse_encode(self.last_change_log_hash, serializer);
|
||||||
<bool>::sse_encode(self.hide_change_log, serializer);
|
<bool>::sse_encode(self.hide_change_log, serializer);
|
||||||
|
<Option<String>>::sse_encode(self.last_release_notes_version, serializer);
|
||||||
<bool>::sse_encode(self.hide_memories_backup_promo, serializer);
|
<bool>::sse_encode(self.hide_memories_backup_promo, serializer);
|
||||||
<bool>::sse_encode(self.hide_widget_share_explainer, serializer);
|
<bool>::sse_encode(self.hide_widget_share_explainer, serializer);
|
||||||
<bool>::sse_encode(self.update_fcm_token, serializer);
|
<bool>::sse_encode(self.update_fcm_token, serializer);
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,13 @@ impl ContactService {
|
||||||
.build()
|
.build()
|
||||||
.insert_on_conflict_update(&mut transaction)
|
.insert_on_conflict_update(&mut transaction)
|
||||||
.await?;
|
.await?;
|
||||||
|
if let Some(joined_at) = user.joined_at {
|
||||||
|
sqlx::query("UPDATE contacts SET joined_at = ? WHERE user_id = ?")
|
||||||
|
.bind(joined_at)
|
||||||
|
.bind(user.user_id)
|
||||||
|
.execute(&mut *transaction)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
transaction.commit().await?;
|
transaction.commit().await?;
|
||||||
|
|
||||||
self.send_contact_request(
|
self.send_contact_request(
|
||||||
|
|
@ -113,10 +120,12 @@ impl ContactService {
|
||||||
let database = self.ctx.app_db.read().await.clone();
|
let database = self.ctx.app_db.read().await.clone();
|
||||||
// The server answered with a bundle, so a previous `UserIdNotFound`
|
// The server answered with a bundle, so a previous `UserIdNotFound`
|
||||||
// (or a manual mark) must not keep the contact blocked.
|
// (or a manual mark) must not keep the contact blocked.
|
||||||
sqlx::query!(
|
sqlx::query(
|
||||||
"UPDATE contacts SET signal_version = 'v2', account_deleted = 0 WHERE user_id = ?",
|
"UPDATE contacts SET signal_version = 'v2', account_deleted = 0, \
|
||||||
user_id
|
joined_at = COALESCE(?, joined_at) WHERE user_id = ?",
|
||||||
)
|
)
|
||||||
|
.bind(user.joined_at)
|
||||||
|
.bind(user_id)
|
||||||
.execute(&database.pool)
|
.execute(&database.pool)
|
||||||
.await?;
|
.await?;
|
||||||
release_deferred_receipts(&database, user_id).await?;
|
release_deferred_receipts(&database, user_id).await?;
|
||||||
|
|
|
||||||
|
|
@ -361,6 +361,10 @@ pub struct UserConfig {
|
||||||
#[serde(default = "defaults::true_value")]
|
#[serde(default = "defaults::true_value")]
|
||||||
#[frb(non_final)]
|
#[frb(non_final)]
|
||||||
pub hide_change_log: bool,
|
pub hide_change_log: bool,
|
||||||
|
/// Last in-app release note the user dismissed.
|
||||||
|
#[serde(default)]
|
||||||
|
#[frb(non_final)]
|
||||||
|
pub last_release_notes_version: Option<String>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
#[frb(non_final)]
|
#[frb(non_final)]
|
||||||
pub hide_memories_backup_promo: bool,
|
pub hide_memories_backup_promo: bool,
|
||||||
|
|
@ -551,6 +555,7 @@ mod tests {
|
||||||
);
|
);
|
||||||
assert!(!config.is_user_discovery_enabled);
|
assert!(!config.is_user_discovery_enabled);
|
||||||
assert_eq!(config.last_server_message_at, None);
|
assert_eq!(config.last_server_message_at, None);
|
||||||
|
assert_eq!(config.last_release_notes_version, None);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
||||||
57
test/visual/components/release_notes_test.dart
Normal file
57
test/visual/components/release_notes_test.dart
Normal file
|
|
@ -0,0 +1,57 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:twonly/src/visual/components/release_notes.comp.dart';
|
||||||
|
import 'package:twonly/src/visual/elements/my_button.element.dart';
|
||||||
|
|
||||||
|
const _releaseNotes = ReleaseNotesData(
|
||||||
|
version: '1.2.3',
|
||||||
|
title: "What's new",
|
||||||
|
introduction: 'A short introduction.',
|
||||||
|
additionalChangesTitle: 'Also improved',
|
||||||
|
closeLabel: 'Close',
|
||||||
|
features: [
|
||||||
|
ReleaseNoteFeature(
|
||||||
|
icon: Icon(Icons.star_rounded),
|
||||||
|
title: 'First feature',
|
||||||
|
description: 'A short feature description.',
|
||||||
|
),
|
||||||
|
],
|
||||||
|
additionalChanges: ['One more improvement'],
|
||||||
|
);
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
testWidgets('shows generic release notes at 80 percent height', (
|
||||||
|
tester,
|
||||||
|
) async {
|
||||||
|
await tester.pumpWidget(
|
||||||
|
MaterialApp(
|
||||||
|
home: Builder(
|
||||||
|
builder: (context) => TextButton(
|
||||||
|
onPressed: () => showReleaseNotesBottomSheet(
|
||||||
|
context,
|
||||||
|
_releaseNotes,
|
||||||
|
),
|
||||||
|
child: const Text('Open'),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
await tester.tap(find.text('Open'));
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
expect(find.text('v1.2.3'), findsOneWidget);
|
||||||
|
expect(find.text("What's new"), findsOneWidget);
|
||||||
|
expect(find.text('First feature'), findsOneWidget);
|
||||||
|
expect(find.text('One more improvement'), findsOneWidget);
|
||||||
|
expect(find.byType(MyButton), findsOneWidget);
|
||||||
|
|
||||||
|
final sheet = find.byType(ReleaseNotesBottomSheet);
|
||||||
|
final mediaSize = MediaQuery.sizeOf(tester.element(sheet));
|
||||||
|
expect(tester.getSize(sheet).height, closeTo(mediaSize.height * 0.8, 0.1));
|
||||||
|
|
||||||
|
await tester.tap(find.byType(MyButton));
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
expect(sheet, findsNothing);
|
||||||
|
});
|
||||||
|
}
|
||||||
48
test/visual/contact_joined_at_test.dart
Normal file
48
test/visual/contact_joined_at_test.dart
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
import 'package:clock/clock.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:twonly/src/localization/generated/app_localizations.dart';
|
||||||
|
import 'package:twonly/src/utils/misc.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
testWidgets('formats contact join age into friendly calendar ranges', (
|
||||||
|
tester,
|
||||||
|
) async {
|
||||||
|
final now = DateTime.utc(2026, 10, 5, 12);
|
||||||
|
late BuildContext context;
|
||||||
|
await tester.pumpWidget(
|
||||||
|
MaterialApp(
|
||||||
|
localizationsDelegates: const [
|
||||||
|
AppLocalizations.delegate,
|
||||||
|
GlobalMaterialLocalizations.delegate,
|
||||||
|
GlobalWidgetsLocalizations.delegate,
|
||||||
|
GlobalCupertinoLocalizations.delegate,
|
||||||
|
],
|
||||||
|
supportedLocales: AppLocalizations.supportedLocales,
|
||||||
|
home: Builder(
|
||||||
|
builder: (buildContext) {
|
||||||
|
context = buildContext;
|
||||||
|
return const SizedBox.shrink();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
withClock(Clock.fixed(now), () {
|
||||||
|
expect(formatJoinedAt(context, now), 'Joined today');
|
||||||
|
expect(
|
||||||
|
formatJoinedAt(context, now.subtract(const Duration(days: 20))),
|
||||||
|
'Joined 20 days ago',
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
formatJoinedAt(context, now.subtract(const Duration(days: 60))),
|
||||||
|
'Joined 2 months ago',
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
formatJoinedAt(context, now.subtract(const Duration(days: 730))),
|
||||||
|
'Joined 2 years ago',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue