Merge branch 'trunk' into fixinstsys
continuous-integration/drone/pr Build is pending Details

This commit is contained in:
Sarah Jamie Lewis 2023-04-21 17:51:29 +00:00
commit 0f749d6b90
18 changed files with 144 additions and 81 deletions

View File

@ -1 +1 @@
2023-04-05-19-46-v0.0.3-13-gb7a4bc2
2023-04-20-15-37-v0.0.3-20-gb2a43b9

View File

@ -442,7 +442,7 @@ class MainActivity: FlutterActivity() {
val profile: String = call.argument("ProfileOnion") ?: ""
val conversation: Int = call.argument("conversation") ?: 0
val fileKey: String = call.argument("fileKey") ?: ""
Cwtch.verifyOrResumeDownload(profile, conversation.toLong(), fileKey)
Cwtch.verifyOrResumeDownloadDefaultLimit(profile, conversation.toLong(), fileKey)
}
"UpdateSettings" -> {
val json: String = call.argument("json") ?: ""

View File

@ -379,8 +379,8 @@ class CwtchNotifier {
});
profileCN.getProfile(data["ProfileOnion"])?.contactList.resort();
break;
case "NewRetValMessageFromPeer":
if (data["Path"] == "profile.name" && data["Exists"] == "true") {
case "UpdatedConversationAttribute":
if (data["Path"] == "profile.name") {
if (data["Data"].toString().trim().length > 0) {
// Update locally on the UI...
if (profileCN.getProfile(data["ProfileOnion"])?.contactList.findContact(data["RemotePeer"]) != null) {
@ -388,37 +388,31 @@ class CwtchNotifier {
}
}
} else if (data['Path'] == "profile.custom-profile-image") {
if (data["Exists"] == "true") {
EnvironmentConfig.debugLog("received ret val of custom profile image: $data");
String fileKey = data['Data'];
var contact = profileCN.getProfile(data["ProfileOnion"])?.contactList.findContact(data["RemotePeer"]);
if (contact != null) {
profileCN.getProfile(data["ProfileOnion"])?.waitForDownloadComplete(contact.identifier, fileKey);
}
EnvironmentConfig.debugLog("received ret val of custom profile image: $data");
String fileKey = data['Data'];
var contact = profileCN.getProfile(data["ProfileOnion"])?.contactList.findContact(data["RemotePeer"]);
if (contact != null) {
profileCN.getProfile(data["ProfileOnion"])?.waitForDownloadComplete(contact.identifier, fileKey);
}
} else if (data['Path'] == "profile.profile-attribute-1" || data['Path'] == "profile.profile-attribute-2" || data['Path'] == "profile.profile-attribute-3") {
if (data["Exists"] == "true") {
var contact = profileCN.getProfile(data["ProfileOnion"])?.contactList.findContact(data["RemotePeer"]);
if (contact != null) {
switch (data['Path']) {
case "profile.profile-attribute-1":
contact.setAttribute(0, data["Data"]);
break;
case "profile.profile-attribute-2":
contact.setAttribute(1, data["Data"]);
break;
case "profile.profile-attribute-3":
contact.setAttribute(2, data["Data"]);
break;
}
var contact = profileCN.getProfile(data["ProfileOnion"])?.contactList.findContact(data["RemotePeer"]);
if (contact != null) {
switch (data['Path']) {
case "profile.profile-attribute-1":
contact.setAttribute(0, data["Data"]);
break;
case "profile.profile-attribute-2":
contact.setAttribute(1, data["Data"]);
break;
case "profile.profile-attribute-3":
contact.setAttribute(2, data["Data"]);
break;
}
}
} else if (data['Path'] == "profile.profile-status") {
if (data["Exists"] == "true") {
var contact = profileCN.getProfile(data["ProfileOnion"])?.contactList.findContact(data["RemotePeer"]);
if (contact != null) {
contact.setAvailabilityStatus(data['Data']);
}
var contact = profileCN.getProfile(data["ProfileOnion"])?.contactList.findContact(data["RemotePeer"]);
if (contact != null) {
contact.setAvailabilityStatus(data['Data']);
}
} else {
EnvironmentConfig.debugLog("unhandled ret val event: ${data['Path']}");

View File

@ -498,7 +498,7 @@ class CwtchFfi implements Cwtch {
@override
// ignore: non_constant_identifier_names
void VerifyOrResumeDownload(String profileOnion, int contactHandle, String filekey) {
var fn = library.lookup<NativeFunction<void_from_string_int_string_function>>("c_VerifyOrResumeDownload");
var fn = library.lookup<NativeFunction<void_from_string_int_string_function>>("c_VerifyOrResumeDownloadDefaultLimit");
// ignore: non_constant_identifier_names
final VerifyOrResumeDownload = fn.asFunction<VoidFromStringIntStringFn>();
final u1 = profileOnion.toNativeUtf8();

View File

@ -131,7 +131,7 @@ class FlwtchState extends State<Flwtch> with WindowListener {
key: Key('app'),
navigatorKey: navKey,
locale: settings.locale,
showPerformanceOverlay: false,
showPerformanceOverlay: settings.profileMode,
localizationsDelegates: <LocalizationsDelegate<dynamic>>[
AppLocalizations.delegate,
MaterialLocalizationDelegate(),

View File

@ -12,8 +12,6 @@ class AppState extends ChangeNotifier {
String? _selectedProfile;
int? _selectedConversation;
int _initialScrollIndex = 0;
int _hoveredIndex = -1;
int? _selectedIndex;
bool _unreadMessagesBelow = false;
bool _disableFilePicker = false;
bool _focus = true;
@ -59,14 +57,6 @@ class AppState extends ChangeNotifier {
notifyListeners();
}
// Never use this for message lookup - can be a non-indexed value
// e.g. -1
int get hoveredIndex => _hoveredIndex;
set hoveredIndex(int newVal) {
this._hoveredIndex = newVal;
notifyListeners();
}
bool get unreadMessagesBelow => _unreadMessagesBelow;
set unreadMessagesBelow(bool newVal) {
this._unreadMessagesBelow = newVal;

View File

@ -39,6 +39,7 @@ class ContactInfoState extends ChangeNotifier {
final int identifier;
final String onion;
late String _nickname;
late String _localNickname;
late ConversationNotificationPolicy _notificationPolicy;
@ -66,11 +67,14 @@ class ContactInfoState extends ChangeNotifier {
String? _acnCircuit;
MessageDraft _messageDraft = MessageDraft.empty();
var _hoveredIndex = -1;
ContactInfoState(
this.profileOnion,
this.identifier,
this.onion, {
nickname = "",
localNickname = "",
isGroup = false,
accepted = false,
blocked = false,
@ -87,6 +91,7 @@ class ContactInfoState extends ChangeNotifier {
pinned = false,
}) {
this._nickname = nickname;
this._localNickname = localNickname;
this._isGroup = isGroup;
this._accepted = accepted;
this._blocked = blocked;
@ -105,7 +110,13 @@ class ContactInfoState extends ChangeNotifier {
keys = Map<String, GlobalKey<MessageRowState>>();
}
String get nickname => this._nickname;
String get nickname {
if (this._localNickname != "") {
return this._localNickname;
}
return this._nickname;
}
String get savePeerHistory => this._savePeerHistory;
String? get acnCircuit => this._acnCircuit;
@ -144,6 +155,11 @@ class ContactInfoState extends ChangeNotifier {
notifyListeners();
}
set localNickname(String newVal) {
this._localNickname = newVal;
notifyListeners();
}
bool get isGroup => this._isGroup;
set isGroup(bool newVal) {
@ -402,7 +418,15 @@ class ContactInfoState extends ChangeNotifier {
}
String augmentedNickname(BuildContext context) {
return this.nickname + (this.availabilityStatus == ProfileStatusMenu.available ? "" : " (" +this.statusString(context) + ")");
return this.nickname + (this.availabilityStatus == ProfileStatusMenu.available ? "" : " (" + this.statusString(context) + ")");
}
// Never use this for message lookup - can be a non-indexed value
// e.g. -1
int get hoveredIndex => _hoveredIndex;
set hoveredIndex(int newVal) {
this._hoveredIndex = newVal;
notifyListeners();
}
String statusString(BuildContext context) {

View File

@ -8,12 +8,17 @@ class FileDownloadProgress {
DateTime? timeStart;
DateTime? timeEnd;
DateTime? requested;
DateTime lastUpdate = DateTime.now();
FileDownloadProgress(this.chunksTotal, this.timeStart);
double progress() {
return 1.0 * chunksDownloaded / chunksTotal;
}
void markUpdate() {
lastUpdate = DateTime.now();
}
}
String prettyBytes(int bytes) {

View File

@ -33,11 +33,9 @@ class FileMessage extends Message {
int fileSize = shareObj['s'] as int;
String fileKey = rootHash + "." + nonce;
// if (metadata.attributes["file-downloaded"] == "true") {
// if (!Provider.of<ProfileInfoState>(context).downloadKnown(fileKey)) {
Provider.of<FlwtchState>(context, listen: false).cwtch.CheckDownloadStatus(Provider.of<ProfileInfoState>(context, listen: false).onion, fileKey);
// }
//}
if (!Provider.of<ProfileInfoState>(context, listen: false).downloadKnown(fileKey)) {
Provider.of<FlwtchState>(context, listen: false).cwtch.CheckDownloadStatus(Provider.of<ProfileInfoState>(context, listen: false).onion, fileKey);
}
if (!validHash(rootHash, nonce)) {
return MessageRow(MalformedBubble(), index);

View File

@ -67,6 +67,7 @@ class ProfileInfoState extends ChangeNotifier {
this._unreadMessages += contact["numUnread"] as int;
return ContactInfoState(this.onion, contact["identifier"], contact["onion"],
nickname: contact["name"],
localNickname: contact["localname"],
status: contact["status"],
imagePath: contact["picture"],
defaultImagePath: contact["isGroup"] ? contact["picture"] : contact["defaultPicture"],
@ -268,6 +269,7 @@ class ProfileInfoState extends ChangeNotifier {
}
this._downloads[fileKey]!.chunksDownloaded = progress;
this._downloads[fileKey]!.chunksTotal = numChunks;
this._downloads[fileKey]!.markUpdate();
}
notifyListeners();
}
@ -277,6 +279,7 @@ class ProfileInfoState extends ChangeNotifier {
this._downloads[fileKey] = FileDownloadProgress(1, DateTime.now());
}
this._downloads[fileKey]!.gotManifest = true;
this._downloads[fileKey]!.markUpdate();
notifyListeners();
}
@ -301,6 +304,7 @@ class ProfileInfoState extends ChangeNotifier {
this._downloads[fileKey]!.timeEnd = DateTime.now();
this._downloads[fileKey]!.downloadedTo = finalPath;
this._downloads[fileKey]!.complete = true;
this._downloads[fileKey]!.markUpdate();
notifyListeners();
}
}
@ -333,9 +337,13 @@ class ProfileInfoState extends ChangeNotifier {
this._downloads[fileKey]!.interrupted = true;
return true;
}
if (DateTime.now().difference(this._downloads[fileKey]!.lastUpdate) > Duration(minutes: 1)) {
this._downloads[fileKey]!.requested = null;
this._downloads[fileKey]!.interrupted = true;
return true;
}
}
}
return false;
}
@ -343,6 +351,7 @@ class ProfileInfoState extends ChangeNotifier {
if (this._downloads.containsKey(fileKey)) {
this._downloads[fileKey]!.interrupted = false;
this._downloads[fileKey]!.requested = DateTime.now();
this._downloads[fileKey]!.markUpdate();
notifyListeners();
}
}

View File

@ -69,6 +69,15 @@ class Settings extends ChangeNotifier {
String get torCacheDir => _torCacheDir;
// Whether to show the profiling interface, not saved
bool _profileMode = false;
bool get profileMode => _profileMode;
set profileMode(bool newval) {
this._profileMode = newval;
notifyListeners();
}
set useSemanticDebugger(bool newval) {
this._useSemanticDebugger = newval;
notifyListeners();

View File

@ -50,7 +50,7 @@ void selectConversation(BuildContext context, int handle) {
// triggers update in Double/TripleColumnView
Provider.of<AppState>(context, listen: false).initialScrollIndex = unread;
Provider.of<AppState>(context, listen: false).selectedConversation = handle;
Provider.of<AppState>(context, listen: false).hoveredIndex = -1;
Provider.of<ContactInfoState>(context, listen: false).hoveredIndex = -1;
// if in singlepane mode, push to the stack
var isLandscape = Provider.of<AppState>(context, listen: false).isLandscape(context);
if (Provider.of<Settings>(context, listen: false).uiColumns(isLandscape).length == 1) _pushMessageView(context, handle);
@ -164,15 +164,21 @@ class _ContactsViewState extends State<ContactsView> {
itemBuilder: (BuildContext context) => <PopupMenuEntry<ProfileStatusMenu>>[
PopupMenuItem<ProfileStatusMenu>(
value: ProfileStatusMenu.available,
child: Text(AppLocalizations.of(context)!.availabilityStatusAvailable!,),
child: Text(
AppLocalizations.of(context)!.availabilityStatusAvailable!,
),
),
PopupMenuItem<ProfileStatusMenu>(
value: ProfileStatusMenu.away,
child: Text(AppLocalizations.of(context)!.availabilityStatusAway!,),
child: Text(
AppLocalizations.of(context)!.availabilityStatusAway!,
),
),
PopupMenuItem<ProfileStatusMenu>(
value: ProfileStatusMenu.busy,
child: Text(AppLocalizations.of(context)!.availabilityStatusBusy!,),
child: Text(
AppLocalizations.of(context)!.availabilityStatusBusy!,
),
),
],
),

View File

@ -545,6 +545,24 @@ class _GlobalSettingsViewState extends State<GlobalSettingsView> {
child: SelectableText(AppLocalizations.of(context)!.versionBuilddate.replaceAll("%1", EnvironmentConfig.BUILD_VER).replaceAll("%2", EnvironmentConfig.BUILD_DATE)),
)
]),
SwitchListTile(
// TODO: Translate, Remove, OR Hide Prior to Release
title: Text("Show Performance Overlay", style: TextStyle(color: settings.current().mainTextColor)),
subtitle: Text("Display an overlay graph of render time."),
value: settings.profileMode,
onChanged: (bool value) {
setState(() {
if (value) {
settings.profileMode = value;
} else {
settings.profileMode = value;
}
});
},
activeTrackColor: settings.theme.defaultButtonActiveColor,
inactiveTrackColor: settings.theme.defaultButtonDisabledColor,
secondary: Icon(Icons.bar_chart, color: settings.current().mainTextColor),
),
Visibility(
visible: EnvironmentConfig.BUILD_VER == dev_version && !Platform.isAndroid,
child: SwitchListTile(

View File

@ -17,11 +17,9 @@ import 'package:cwtch/models/profile.dart';
import 'package:cwtch/third_party/linkify/flutter_linkify.dart';
import 'package:cwtch/widgets/malformedbubble.dart';
import 'package:cwtch/widgets/messageloadingbubble.dart';
import 'package:cwtch/widgets/messagerow.dart';
import 'package:cwtch/widgets/profileimage.dart';
import 'package:cwtch/controllers/filesharing.dart' as filesharing;
import 'package:cwtch/widgets/staticmessagebubble.dart';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
@ -230,11 +228,12 @@ class _MessageViewState extends State<MessageView> {
),
Expanded(
child: Container(
height: 42,
clipBehavior: Clip.hardEdge,
decoration: BoxDecoration(),
child: Align(
alignment: Alignment.centerLeft, child: Text(
height: 42,
clipBehavior: Clip.hardEdge,
decoration: BoxDecoration(),
child: Align(
alignment: Alignment.centerLeft,
child: Text(
Provider.of<ContactInfoState>(context).augmentedNickname(context),
overflow: TextOverflow.clip,
maxLines: 1,

View File

@ -113,15 +113,24 @@ class _PeerSettingsViewState extends State<PeerSettingsView> {
child: Column(children: [
Padding(
padding: EdgeInsets.all(1),
child: SelectableText(Provider.of<ContactInfoState>(context, listen: false).attributes[0] ?? "", textAlign: TextAlign.center,),
child: SelectableText(
Provider.of<ContactInfoState>(context, listen: false).attributes[0] ?? "",
textAlign: TextAlign.center,
),
),
Padding(
padding: EdgeInsets.all(1),
child: SelectableText(Provider.of<ContactInfoState>(context, listen: false).attributes[1] ?? "", textAlign: TextAlign.center,),
child: SelectableText(
Provider.of<ContactInfoState>(context, listen: false).attributes[1] ?? "",
textAlign: TextAlign.center,
),
),
Padding(
padding: EdgeInsets.all(1),
child: SelectableText(Provider.of<ContactInfoState>(context, listen: false).attributes[2] ?? "", textAlign: TextAlign.center,),
child: SelectableText(
Provider.of<ContactInfoState>(context, listen: false).attributes[2] ?? "",
textAlign: TextAlign.center,
),
)
]))
]),
@ -137,7 +146,7 @@ class _PeerSettingsViewState extends State<PeerSettingsView> {
onPressed: () {
var profileOnion = Provider.of<ContactInfoState>(context, listen: false).profileOnion;
var conversation = Provider.of<ContactInfoState>(context, listen: false).identifier;
Provider.of<ContactInfoState>(context, listen: false).nickname = ctrlrNick.text;
Provider.of<ContactInfoState>(context, listen: false).localNickname = ctrlrNick.text;
Provider.of<FlwtchState>(context, listen: false).cwtch.SetConversationAttribute(profileOnion, conversation, "profile.name", ctrlrNick.text);
final snackBar = SnackBar(content: Text(AppLocalizations.of(context)!.nickChangeSuccess));
ScaffoldMessenger.of(context).showSnackBar(snackBar);

View File

@ -165,7 +165,7 @@ class FileBubbleState extends State<FileBubble> {
wdgDecorations = Text('\u202F');
} else if (downloadComplete && path != null) {
// in this case, whatever marked download.complete would have also set the path
if (Provider.of<Settings>(context).shouldPreview(path)) {
if (myFile != null && Provider.of<Settings>(context).shouldPreview(path)) {
isPreview = true;
wdgDecorations = Center(
widthFactor: 1.0,
@ -196,6 +196,7 @@ class FileBubbleState extends State<FileBubble> {
// so we probably have to request an info lookup
if (!downloadInterrupted) {
wdgDecorations = Text(AppLocalizations.of(context)!.fileCheckingStatus + '...' + '\u202F');
// We should have already requested this...
} else {
var path = Provider.of<ProfileInfoState>(context).downloadFinalPath(widget.fileKey()) ?? "";
wdgDecorations = Visibility(

View File

@ -1,3 +1,4 @@
import 'package:cwtch/config.dart';
import 'package:cwtch/models/appstate.dart';
import 'package:cwtch/models/contact.dart';
import 'package:cwtch/models/message.dart';

View File

@ -81,7 +81,7 @@ class MessageRowState extends State<MessageRow> with SingleTickerProviderStateMi
Widget wdgReply = Platform.isAndroid
? SizedBox.shrink()
: Visibility(
visible: EnvironmentConfig.TEST_MODE || Provider.of<AppState>(context).hoveredIndex == Provider.of<MessageMetadata>(context).messageID,
visible: EnvironmentConfig.TEST_MODE || Provider.of<ContactInfoState>(context).hoveredIndex == Provider.of<MessageMetadata>(context).messageID,
maintainSize: true,
maintainAnimation: true,
maintainState: true,
@ -106,7 +106,7 @@ class MessageRowState extends State<MessageRow> with SingleTickerProviderStateMi
Widget wdgSeeReplies = Platform.isAndroid
? SizedBox.shrink()
: Visibility(
visible: EnvironmentConfig.TEST_MODE || Provider.of<AppState>(context).hoveredIndex == Provider.of<MessageMetadata>(context).messageID,
visible: EnvironmentConfig.TEST_MODE || Provider.of<ContactInfoState>(context).hoveredIndex == Provider.of<MessageMetadata>(context).messageID,
maintainSize: true,
maintainAnimation: true,
maintainState: true,
@ -128,8 +128,8 @@ class MessageRowState extends State<MessageRow> with SingleTickerProviderStateMi
: Visibility(
visible: Provider.of<FlwtchState>(context, listen: false).cwtch.IsBlodeuweddSupported() &&
Provider.of<Settings>(context).isExperimentEnabled(BlodeuweddExperiment) &&
(EnvironmentConfig.TEST_MODE || Provider.of<AppState>(context).hoveredIndex == Provider.of<MessageMetadata>(context).messageID),
maintainSize: false,
(EnvironmentConfig.TEST_MODE || Provider.of<ContactInfoState>(context).hoveredIndex == Provider.of<MessageMetadata>(context).messageID),
maintainSize: true,
maintainAnimation: true,
maintainState: true,
maintainInteractivity: false,
@ -245,16 +245,12 @@ class MessageRowState extends State<MessageRow> with SingleTickerProviderStateMi
var mr = MouseRegion(
// For desktop...
onHover: (event) {
if (Provider.of<AppState>(context, listen: false).hoveredIndex != Provider.of<MessageMetadata>(context, listen: false).messageID) {
setState(() {
Provider.of<AppState>(context, listen: false).hoveredIndex = Provider.of<MessageMetadata>(context, listen: false).messageID;
});
if (Provider.of<ContactInfoState>(context, listen: false).hoveredIndex != Provider.of<MessageMetadata>(context, listen: false).messageID) {
Provider.of<ContactInfoState>(context, listen: false).hoveredIndex = Provider.of<MessageMetadata>(context, listen: false).messageID;
}
},
onExit: (event) {
// setState(() {
// Provider.of<AppState>(context, listen: false).hoveredIndex = -1;
//});
Provider.of<ContactInfoState>(context, listen: false).hoveredIndex = -1;
},
child: GestureDetector(
onPanUpdate: (details) {
@ -270,12 +266,16 @@ class MessageRowState extends State<MessageRow> with SingleTickerProviderStateMi
},
onPanEnd: (details) {
_runAnimation(details.velocity.pixelsPerSecond, size);
Provider.of<ContactInfoState>(context, listen: false).messageDraft.quotedReference = Provider.of<MessageMetadata>(context, listen: false).messageID;
Provider.of<ContactInfoState>(context, listen: false).notifyMessageDraftUpdate();
setState(() {});
if (Platform.isAndroid) {
Provider.of<ContactInfoState>(context, listen: false).messageDraft.quotedReference = Provider.of<MessageMetadata>(context, listen: false).messageID;
Provider.of<ContactInfoState>(context, listen: false).notifyMessageDraftUpdate();
setState(() {});
}
},
onLongPress: () async {
modalShowReplies(context, AppLocalizations.of(context)!.headingReplies, AppLocalizations.of(context)!.messageNoReplies, settings, pis, cis, borderColor, cache, messageID);
if (Platform.isAndroid) {
modalShowReplies(context, AppLocalizations.of(context)!.headingReplies, AppLocalizations.of(context)!.messageNoReplies, settings, pis, cis, borderColor, cache, messageID);
}
},
child: Padding(
padding: EdgeInsets.all(2),