mirror of
https://github.com/twonlyapp/twonly-app.git
synced 2026-01-15 07:48:40 +00:00
updating profile and minor issues
This commit is contained in:
parent
746887b845
commit
7fe0f16a5c
15 changed files with 124 additions and 176 deletions
|
|
@ -1,4 +1,5 @@
|
|||
import 'package:drift/drift.dart';
|
||||
import 'package:twonly/globals.dart';
|
||||
import 'package:twonly/src/database/tables/contacts.table.dart';
|
||||
import 'package:twonly/src/database/twonly.db.dart';
|
||||
import 'package:twonly/src/database/twonly_database_old.dart' as old;
|
||||
|
|
@ -45,6 +46,15 @@ class ContactsDao extends DatabaseAccessor<TwonlyDB> with _$ContactsDaoMixin {
|
|||
final contact = await getContactByUserId(userId).getSingleOrNull();
|
||||
if (contact != null) {
|
||||
await updatePushUser(contact);
|
||||
final group = await twonlyDB.groupsDao.getDirectChat(userId);
|
||||
if (group != null) {
|
||||
await twonlyDB.groupsDao.updateGroup(
|
||||
group.groupId,
|
||||
GroupsCompanion(
|
||||
groupName: Value(getContactDisplayName(contact)),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,8 +26,7 @@ class Messages extends Table {
|
|||
|
||||
BlobColumn get downloadToken => blob().nullable()();
|
||||
|
||||
TextColumn get quotesMessageId =>
|
||||
text().nullable().references(Messages, #messageId)();
|
||||
TextColumn get quotesMessageId => text().nullable()();
|
||||
|
||||
BoolColumn get isDeletedFromSender =>
|
||||
boolean().withDefault(const Constant(false))();
|
||||
|
|
|
|||
|
|
@ -2265,10 +2265,7 @@ class $MessagesTable extends Messages with TableInfo<$MessagesTable, Message> {
|
|||
@override
|
||||
late final GeneratedColumn<String> quotesMessageId = GeneratedColumn<String>(
|
||||
'quotes_message_id', aliasedName, true,
|
||||
type: DriftSqlType.string,
|
||||
requiredDuringInsert: false,
|
||||
defaultConstraints: GeneratedColumn.constraintIsAlways(
|
||||
'REFERENCES messages (message_id)'));
|
||||
type: DriftSqlType.string, requiredDuringInsert: false);
|
||||
static const VerificationMeta _isDeletedFromSenderMeta =
|
||||
const VerificationMeta('isDeletedFromSender');
|
||||
@override
|
||||
|
|
@ -8207,21 +8204,6 @@ final class $$MessagesTableReferences
|
|||
manager.$state.copyWith(prefetchedData: [item]));
|
||||
}
|
||||
|
||||
static $MessagesTable _quotesMessageIdTable(_$TwonlyDB db) =>
|
||||
db.messages.createAlias($_aliasNameGenerator(
|
||||
db.messages.quotesMessageId, db.messages.messageId));
|
||||
|
||||
$$MessagesTableProcessedTableManager? get quotesMessageId {
|
||||
final $_column = $_itemColumn<String>('quotes_message_id');
|
||||
if ($_column == null) return null;
|
||||
final manager = $$MessagesTableTableManager($_db, $_db.messages)
|
||||
.filter((f) => f.messageId.sqlEquals($_column));
|
||||
final item = $_typedResult.readTableOrNull(_quotesMessageIdTable($_db));
|
||||
if (item == null) return manager;
|
||||
return ProcessedTableManager(
|
||||
manager.$state.copyWith(prefetchedData: [item]));
|
||||
}
|
||||
|
||||
static MultiTypedResultKey<$MessageHistoriesTable, List<MessageHistory>>
|
||||
_messageHistoriesRefsTable(_$TwonlyDB db) =>
|
||||
MultiTypedResultKey.fromTable(db.messageHistories,
|
||||
|
|
@ -8315,6 +8297,10 @@ class $$MessagesTableFilterComposer
|
|||
ColumnFilters<Uint8List> get downloadToken => $composableBuilder(
|
||||
column: $table.downloadToken, builder: (column) => ColumnFilters(column));
|
||||
|
||||
ColumnFilters<String> get quotesMessageId => $composableBuilder(
|
||||
column: $table.quotesMessageId,
|
||||
builder: (column) => ColumnFilters(column));
|
||||
|
||||
ColumnFilters<bool> get isDeletedFromSender => $composableBuilder(
|
||||
column: $table.isDeletedFromSender,
|
||||
builder: (column) => ColumnFilters(column));
|
||||
|
|
@ -8394,26 +8380,6 @@ class $$MessagesTableFilterComposer
|
|||
return composer;
|
||||
}
|
||||
|
||||
$$MessagesTableFilterComposer get quotesMessageId {
|
||||
final $$MessagesTableFilterComposer composer = $composerBuilder(
|
||||
composer: this,
|
||||
getCurrentColumn: (t) => t.quotesMessageId,
|
||||
referencedTable: $db.messages,
|
||||
getReferencedColumn: (t) => t.messageId,
|
||||
builder: (joinBuilder,
|
||||
{$addJoinBuilderToRootComposer,
|
||||
$removeJoinBuilderFromRootComposer}) =>
|
||||
$$MessagesTableFilterComposer(
|
||||
$db: $db,
|
||||
$table: $db.messages,
|
||||
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
|
||||
joinBuilder: joinBuilder,
|
||||
$removeJoinBuilderFromRootComposer:
|
||||
$removeJoinBuilderFromRootComposer,
|
||||
));
|
||||
return composer;
|
||||
}
|
||||
|
||||
Expression<bool> messageHistoriesRefs(
|
||||
Expression<bool> Function($$MessageHistoriesTableFilterComposer f) f) {
|
||||
final $$MessageHistoriesTableFilterComposer composer = $composerBuilder(
|
||||
|
|
@ -8524,6 +8490,10 @@ class $$MessagesTableOrderingComposer
|
|||
column: $table.downloadToken,
|
||||
builder: (column) => ColumnOrderings(column));
|
||||
|
||||
ColumnOrderings<String> get quotesMessageId => $composableBuilder(
|
||||
column: $table.quotesMessageId,
|
||||
builder: (column) => ColumnOrderings(column));
|
||||
|
||||
ColumnOrderings<bool> get isDeletedFromSender => $composableBuilder(
|
||||
column: $table.isDeletedFromSender,
|
||||
builder: (column) => ColumnOrderings(column));
|
||||
|
|
@ -8602,26 +8572,6 @@ class $$MessagesTableOrderingComposer
|
|||
));
|
||||
return composer;
|
||||
}
|
||||
|
||||
$$MessagesTableOrderingComposer get quotesMessageId {
|
||||
final $$MessagesTableOrderingComposer composer = $composerBuilder(
|
||||
composer: this,
|
||||
getCurrentColumn: (t) => t.quotesMessageId,
|
||||
referencedTable: $db.messages,
|
||||
getReferencedColumn: (t) => t.messageId,
|
||||
builder: (joinBuilder,
|
||||
{$addJoinBuilderToRootComposer,
|
||||
$removeJoinBuilderFromRootComposer}) =>
|
||||
$$MessagesTableOrderingComposer(
|
||||
$db: $db,
|
||||
$table: $db.messages,
|
||||
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
|
||||
joinBuilder: joinBuilder,
|
||||
$removeJoinBuilderFromRootComposer:
|
||||
$removeJoinBuilderFromRootComposer,
|
||||
));
|
||||
return composer;
|
||||
}
|
||||
}
|
||||
|
||||
class $$MessagesTableAnnotationComposer
|
||||
|
|
@ -8648,6 +8598,9 @@ class $$MessagesTableAnnotationComposer
|
|||
GeneratedColumn<Uint8List> get downloadToken => $composableBuilder(
|
||||
column: $table.downloadToken, builder: (column) => column);
|
||||
|
||||
GeneratedColumn<String> get quotesMessageId => $composableBuilder(
|
||||
column: $table.quotesMessageId, builder: (column) => column);
|
||||
|
||||
GeneratedColumn<bool> get isDeletedFromSender => $composableBuilder(
|
||||
column: $table.isDeletedFromSender, builder: (column) => column);
|
||||
|
||||
|
|
@ -8726,26 +8679,6 @@ class $$MessagesTableAnnotationComposer
|
|||
return composer;
|
||||
}
|
||||
|
||||
$$MessagesTableAnnotationComposer get quotesMessageId {
|
||||
final $$MessagesTableAnnotationComposer composer = $composerBuilder(
|
||||
composer: this,
|
||||
getCurrentColumn: (t) => t.quotesMessageId,
|
||||
referencedTable: $db.messages,
|
||||
getReferencedColumn: (t) => t.messageId,
|
||||
builder: (joinBuilder,
|
||||
{$addJoinBuilderToRootComposer,
|
||||
$removeJoinBuilderFromRootComposer}) =>
|
||||
$$MessagesTableAnnotationComposer(
|
||||
$db: $db,
|
||||
$table: $db.messages,
|
||||
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
|
||||
joinBuilder: joinBuilder,
|
||||
$removeJoinBuilderFromRootComposer:
|
||||
$removeJoinBuilderFromRootComposer,
|
||||
));
|
||||
return composer;
|
||||
}
|
||||
|
||||
Expression<T> messageHistoriesRefs<T extends Object>(
|
||||
Expression<T> Function($$MessageHistoriesTableAnnotationComposer a) f) {
|
||||
final $$MessageHistoriesTableAnnotationComposer composer = $composerBuilder(
|
||||
|
|
@ -8846,7 +8779,6 @@ class $$MessagesTableTableManager extends RootTableManager<
|
|||
{bool groupId,
|
||||
bool senderId,
|
||||
bool mediaId,
|
||||
bool quotesMessageId,
|
||||
bool messageHistoriesRefs,
|
||||
bool reactionsRefs,
|
||||
bool receiptsRefs,
|
||||
|
|
@ -8941,7 +8873,6 @@ class $$MessagesTableTableManager extends RootTableManager<
|
|||
{groupId = false,
|
||||
senderId = false,
|
||||
mediaId = false,
|
||||
quotesMessageId = false,
|
||||
messageHistoriesRefs = false,
|
||||
reactionsRefs = false,
|
||||
receiptsRefs = false,
|
||||
|
|
@ -8997,17 +8928,6 @@ class $$MessagesTableTableManager extends RootTableManager<
|
|||
$$MessagesTableReferences._mediaIdTable(db).mediaId,
|
||||
) as T;
|
||||
}
|
||||
if (quotesMessageId) {
|
||||
state = state.withJoin(
|
||||
currentTable: table,
|
||||
currentColumn: table.quotesMessageId,
|
||||
referencedTable:
|
||||
$$MessagesTableReferences._quotesMessageIdTable(db),
|
||||
referencedColumn: $$MessagesTableReferences
|
||||
._quotesMessageIdTable(db)
|
||||
.messageId,
|
||||
) as T;
|
||||
}
|
||||
|
||||
return state;
|
||||
},
|
||||
|
|
@ -9086,7 +9006,6 @@ typedef $$MessagesTableProcessedTableManager = ProcessedTableManager<
|
|||
{bool groupId,
|
||||
bool senderId,
|
||||
bool mediaId,
|
||||
bool quotesMessageId,
|
||||
bool messageHistoriesRefs,
|
||||
bool reactionsRefs,
|
||||
bool receiptsRefs,
|
||||
|
|
|
|||
|
|
@ -341,5 +341,6 @@
|
|||
"reportUserReason": "Meldegrund",
|
||||
"reportUser": "Benutzer melden",
|
||||
"newDeviceRegistered": "Du hast dich auf einem anderen Gerät angemeldet. Daher wurdest du hier abgemeldet.",
|
||||
"tabToRemoveEmoji": "Tippen um zu entfernen"
|
||||
"tabToRemoveEmoji": "Tippen um zu entfernen",
|
||||
"quotedMessageWasDeleted": "Die zitierte Nachricht wurde gelöscht."
|
||||
}
|
||||
|
|
@ -497,5 +497,6 @@
|
|||
"reportUserReason": "Reporting reason",
|
||||
"reportUser": "Report user",
|
||||
"newDeviceRegistered": "You have logged in on another device. You have therefore been logged out here.",
|
||||
"tabToRemoveEmoji": "Tab to remove"
|
||||
"tabToRemoveEmoji": "Tab to remove",
|
||||
"quotedMessageWasDeleted": "The quoted message has been deleted."
|
||||
}
|
||||
|
|
@ -2089,6 +2089,12 @@ abstract class AppLocalizations {
|
|||
/// In en, this message translates to:
|
||||
/// **'Tab to remove'**
|
||||
String get tabToRemoveEmoji;
|
||||
|
||||
/// No description provided for @quotedMessageWasDeleted.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'The quoted message has been deleted.'**
|
||||
String get quotedMessageWasDeleted;
|
||||
}
|
||||
|
||||
class _AppLocalizationsDelegate
|
||||
|
|
|
|||
|
|
@ -1109,4 +1109,8 @@ class AppLocalizationsDe extends AppLocalizations {
|
|||
|
||||
@override
|
||||
String get tabToRemoveEmoji => 'Tippen um zu entfernen';
|
||||
|
||||
@override
|
||||
String get quotedMessageWasDeleted =>
|
||||
'Die zitierte Nachricht wurde gelöscht.';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1103,4 +1103,7 @@ class AppLocalizationsEn extends AppLocalizations {
|
|||
|
||||
@override
|
||||
String get tabToRemoveEmoji => 'Tab to remove';
|
||||
|
||||
@override
|
||||
String get quotedMessageWasDeleted => 'The quoted message has been deleted.';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -214,6 +214,8 @@ Future<(Uint8List, Uint8List?)?> sendCipherText(
|
|||
bool onlyReturnEncryptedData = false,
|
||||
String? messageId,
|
||||
}) async {
|
||||
encryptedContent.senderProfileCounter = Int64(gUser.avatarCounter);
|
||||
|
||||
final response = pb.Message()
|
||||
..type = pb.Message_Type.CIPHERTEXT
|
||||
..encryptedContent = encryptedContent.writeToBuffer();
|
||||
|
|
|
|||
|
|
@ -106,19 +106,21 @@ Future<int?> checkForProfileUpdate(
|
|||
) async {
|
||||
int? senderProfileCounter;
|
||||
|
||||
if (content.hasSenderProfileCounter() && !content.hasContactUpdate()) {
|
||||
if (content.hasSenderProfileCounter()) {
|
||||
senderProfileCounter = content.senderProfileCounter.toInt();
|
||||
final contact = await twonlyDB.contactsDao
|
||||
.getContactByUserId(fromUserId)
|
||||
.getSingleOrNull();
|
||||
if (contact != null) {
|
||||
if (contact.senderProfileCounter < senderProfileCounter) {
|
||||
await sendCipherText(
|
||||
fromUserId,
|
||||
EncryptedContent()
|
||||
..contactUpdate = (EncryptedContent_ContactUpdate()
|
||||
..type = EncryptedContent_ContactUpdate_Type.REQUEST),
|
||||
);
|
||||
if (!content.hasContactUpdate()) {
|
||||
final contact = await twonlyDB.contactsDao
|
||||
.getContactByUserId(fromUserId)
|
||||
.getSingleOrNull();
|
||||
if (contact != null) {
|
||||
if (contact.senderProfileCounter < senderProfileCounter) {
|
||||
await sendCipherText(
|
||||
fromUserId,
|
||||
EncryptedContent()
|
||||
..contactUpdate = (EncryptedContent_ContactUpdate()
|
||||
..type = EncryptedContent_ContactUpdate_Type.REQUEST),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -277,7 +277,7 @@ class _ChatMessagesViewState extends State<ChatMessagesView> {
|
|||
return Transform.translate(
|
||||
offset: Offset(
|
||||
(focusedScrollItem == i)
|
||||
? (chatMessage.quotesMessageId == null)
|
||||
? (chatMessage.senderId == null)
|
||||
? -8
|
||||
: 8
|
||||
: 0,
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ class ChatTextEntry extends StatelessWidget {
|
|||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
children: [
|
||||
if (measureTextWidth(text) > 270)
|
||||
if (measureTextWidth(text) > 270 || message.quotesMessageId != null)
|
||||
Expanded(
|
||||
child: BetterText(text: text),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -76,12 +76,14 @@ class _MessageSendStateIconState extends State<MessageSendStateIcon> {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final icons = <Widget>[];
|
||||
var icons = <Widget>[];
|
||||
var text = '';
|
||||
Widget? textWidget;
|
||||
textWidget = null;
|
||||
final kindsAlreadyShown = HashSet<MessageType>();
|
||||
|
||||
var hasLoader = false;
|
||||
|
||||
for (final message in widget.messages) {
|
||||
if (icons.length == 2) break;
|
||||
if (kindsAlreadyShown.contains(message.type)) continue;
|
||||
|
|
@ -130,6 +132,7 @@ class _MessageSendStateIconState extends State<MessageSendStateIcon> {
|
|||
if (mediaFile.downloadState == DownloadState.downloading) {
|
||||
text = context.lang.messageSendState_Loading;
|
||||
icon = getLoaderIcon(color);
|
||||
hasLoader = true;
|
||||
}
|
||||
}
|
||||
case MessageSendState.send:
|
||||
|
|
@ -139,9 +142,11 @@ class _MessageSendStateIconState extends State<MessageSendStateIcon> {
|
|||
case MessageSendState.sending:
|
||||
icon = getLoaderIcon(color);
|
||||
text = context.lang.messageSendState_Sending;
|
||||
hasLoader = true;
|
||||
case MessageSendState.receiving:
|
||||
icon = getLoaderIcon(color);
|
||||
text = context.lang.messageSendState_Received;
|
||||
hasLoader = true;
|
||||
}
|
||||
|
||||
if (message.mediaStored) {
|
||||
|
|
@ -165,6 +170,11 @@ class _MessageSendStateIconState extends State<MessageSendStateIcon> {
|
|||
}
|
||||
}
|
||||
|
||||
if (hasLoader) {
|
||||
icons = [icon];
|
||||
break;
|
||||
}
|
||||
|
||||
if (message.type == MessageType.media) {
|
||||
icons.insert(0, icon);
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -150,53 +150,58 @@ class _ResponsePreviewState extends State<ResponsePreview> {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (message == null) return Container();
|
||||
String? subtitle;
|
||||
var color = const Color.fromARGB(233, 68, 137, 255);
|
||||
var username = '';
|
||||
|
||||
if (message!.type == MessageType.text) {
|
||||
if (message!.content != null) {
|
||||
subtitle = truncateString(message!.content!);
|
||||
if (message != null) {
|
||||
if (message!.type == MessageType.text) {
|
||||
if (message!.content != null) {
|
||||
subtitle = truncateString(message!.content!);
|
||||
}
|
||||
}
|
||||
if (message!.type == MessageType.media && mediaService != null) {
|
||||
subtitle = mediaService!.mediaFile.type == MediaType.video
|
||||
? context.lang.video
|
||||
: context.lang.image;
|
||||
}
|
||||
}
|
||||
if (message!.type == MessageType.media && mediaService != null) {
|
||||
subtitle = mediaService!.mediaFile.type == MediaType.video
|
||||
? context.lang.video
|
||||
: context.lang.image;
|
||||
}
|
||||
|
||||
var username = context.lang.you;
|
||||
if (message!.senderId != null) {
|
||||
username = message!.senderId.toString();
|
||||
}
|
||||
username = context.lang.you;
|
||||
if (message!.senderId != null) {
|
||||
username = message!.senderId.toString();
|
||||
}
|
||||
|
||||
final color = getMessageColor(message!);
|
||||
color = getMessageColor(message!);
|
||||
|
||||
if (!message!.mediaStored) {
|
||||
return Container(
|
||||
padding: widget.showBorder
|
||||
? const EdgeInsets.only(left: 10, right: 10)
|
||||
: const EdgeInsets.symmetric(horizontal: 5),
|
||||
decoration: (widget.showBorder)
|
||||
? BoxDecoration(
|
||||
border: Border(
|
||||
left: BorderSide(
|
||||
color: color,
|
||||
width: 2,
|
||||
if (!message!.mediaStored) {
|
||||
return Container(
|
||||
padding: widget.showBorder
|
||||
? const EdgeInsets.only(left: 10, right: 10)
|
||||
: const EdgeInsets.symmetric(horizontal: 5),
|
||||
decoration: (widget.showBorder)
|
||||
? BoxDecoration(
|
||||
border: Border(
|
||||
left: BorderSide(
|
||||
color: color,
|
||||
width: 2,
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
: null,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
username,
|
||||
style: const TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
if (subtitle != null) Text(subtitle),
|
||||
],
|
||||
),
|
||||
);
|
||||
)
|
||||
: null,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
username,
|
||||
style: const TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
if (subtitle != null) Text(subtitle),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
username = context.lang.quotedMessageWasDeleted;
|
||||
}
|
||||
|
||||
return Container(
|
||||
|
|
@ -227,7 +232,11 @@ class _ResponsePreviewState extends State<ResponsePreview> {
|
|||
if (mediaService != null)
|
||||
SizedBox(
|
||||
height: widget.showBorder ? 100 : 210,
|
||||
child: Image.file(mediaService!.thumbnailPath),
|
||||
child: Image.file(
|
||||
mediaService!.mediaFile.type == MediaType.video
|
||||
? mediaService!.thumbnailPath
|
||||
: mediaService!.storedPath,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
|
|
|||
|
|
@ -469,27 +469,6 @@ class _MediaViewerViewState extends State<MediaViewerView> {
|
|||
child: Image.file(
|
||||
currentMedia!.tempPath,
|
||||
fit: BoxFit.contain,
|
||||
frameBuilder: (
|
||||
context,
|
||||
child,
|
||||
frame,
|
||||
wasSynchronouslyLoaded,
|
||||
) {
|
||||
if (wasSynchronouslyLoaded) return child;
|
||||
return AnimatedSwitcher(
|
||||
duration: const Duration(milliseconds: 200),
|
||||
child: frame != null
|
||||
? child
|
||||
: Container(
|
||||
height: 60,
|
||||
color: Colors.transparent,
|
||||
width: 60,
|
||||
child: const CircularProgressIndicator(
|
||||
strokeWidth: 2,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
|
|
@ -534,13 +513,16 @@ class _MediaViewerViewState extends State<MediaViewerView> {
|
|||
],
|
||||
),
|
||||
),
|
||||
if (currentMedia?.mediaFile.downloadState != DownloadState.ready)
|
||||
if (currentMedia != null &&
|
||||
currentMedia?.mediaFile.downloadState != DownloadState.ready)
|
||||
const Positioned.fill(
|
||||
child: Center(
|
||||
child: SizedBox(
|
||||
height: 60,
|
||||
width: 60,
|
||||
child: CircularProgressIndicator(strokeWidth: 6),
|
||||
child: CircularProgressIndicator(
|
||||
strokeWidth: 6,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
|
|||
Loading…
Reference in a new issue