diff --git a/flutter/TODO.md b/flutter/TODO.md index 1583bd6..45762b9 100644 --- a/flutter/TODO.md +++ b/flutter/TODO.md @@ -2,24 +2,24 @@ # TODO - [x] Message List - * [ ] CRUD + * [x] CRUD - [x] Message Big-View - [x] Search/Filter Messages - [x] Channel List * [x] Show subs - * [ ] CRUD - * [ ] what about unsubbed foreign channels? - thex should still be visible (or should they, do i still get the messages?) + * [x] CRUD + * [x] what about unsubbed foreign channels? - thex should still be visible (or should they, do i still get the messages?) - [x] Sub List * [x] Sub/Unsub/Accept/Deny - [x] Debug List (Show logs, requests) - - [ ] Key List - * [ ] CRUD - - [ ] Auto R-only key for admin, use for QR+link+send + - [x] Key List + * [x] CRUD + - [x] Auto R-only key for admin, use for QR+link+send - [ ] settings - - [ ] notifications - - [ ] push navigation stack - - [ ] read + migrate old SharedPrefs (or not? - who uses SCN even??) - - [ ] Account-Page + - [?] notifications + - [?] push navigation stack + - [/] read + migrate old SharedPrefs (or not? - who uses SCN even??) + - [x] Account-Page - [x] Logout - [x] Send-page @@ -27,10 +27,10 @@ - [x] fix time format (in message-list, in card, top right) - midnight is shown as "24:05" instead of "00:05" - thats weird - - [ ] Add scrollbar + - [x] Add scrollbar -> https://api.flutter.dev/flutter/material/Scrollbar-class.html - - [ ] you cant unsubscribe from foreign channel without completely loosing subscription. + - [x] you cant unsubscribe from foreign channel without completely loosing subscription. perhaps subscriptions should have two cofirmed bool (both must be true to receive messages): confirmed-owner && confirmed-subscriber Then the subscriber can unconfirm his half - without loosing the owner confirmation diff --git a/flutter/_utils/autoreload.sh b/flutter/_utils/autoreload.sh index e33a1e7..f2483ee 100755 --- a/flutter/_utils/autoreload.sh +++ b/flutter/_utils/autoreload.sh @@ -31,10 +31,10 @@ if [ -z "$pids" ]; then exit 1 fi -trap 'echo "reseived SIGNAL - exiting"; exit 0' EXIT -trap 'echo "reseived SIGNAL - exiting"; exit 0' SIGINT -trap 'echo "reseived SIGNAL - exiting"; exit 0' SIGTERM -trap 'echo "reseived SIGNAL - exiting"; exit 0' SIGQUIT +trap 'echo "reseived SIGNAL - exiting"; jobs -p | xargs kill ; exit 0' EXIT +trap 'echo "reseived SIGNAL - exiting"; jobs -p | xargs kill ; exit 0' SIGINT +trap 'echo "reseived SIGNAL - exiting"; jobs -p | xargs kill ; exit 0' SIGTERM +trap 'echo "reseived SIGNAL - exiting"; jobs -p | xargs kill ; exit 0' SIGQUIT echo "" while IFS= read -r pid; do diff --git a/flutter/lib/pages/message_view/message_view.dart b/flutter/lib/pages/message_view/message_view.dart index 17a5932..4152700 100644 --- a/flutter/lib/pages/message_view/message_view.dart +++ b/flutter/lib/pages/message_view/message_view.dart @@ -37,6 +37,8 @@ class _MessageViewPageState extends State { (SCNMessage, ChannelPreview, KeyTokenPreview, UserPreview)? mainFutureSnapshot = null; static final _dateFormat = DateFormat('yyyy-MM-dd HH:mm'); //TODO setting + final ScrollController _controller = ScrollController(); + bool _monospaceMode = false; SCNMessage? message = null; @@ -83,6 +85,7 @@ class _MessageViewPageState extends State { @override void dispose() { + _controller.dispose(); super.dispose(); } @@ -137,77 +140,100 @@ class _MessageViewPageState extends State { Widget _buildMessageView(BuildContext context, SCNMessage message, ChannelPreview? channel, KeyTokenPreview? token, UserPreview? user) { final userAccUserID = context.select((v) => v.userID); - return SingleChildScrollView( - child: Padding( - padding: const EdgeInsets.fromLTRB(24, 16, 24, 16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - ..._buildMessageHeader(context, message, channel), - SizedBox(height: 8), - if (message.content != null) ..._buildMessageContent(context, message), - SizedBox(height: 8), - if (message.senderName != null) - UI.metaCard( - context: context, - icon: FontAwesomeIcons.solidSignature, - title: 'Sender', - values: [message.senderName!], - mainAction: () => { - Navi.push(context, () => FilteredMessageViewPage(title: message.senderName!, filter: MessageFilter(senderNames: [message.senderName!]))) - }, - ), + final child = Padding( + padding: const EdgeInsets.fromLTRB(24, 16, 24, 16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + ..._buildMessageHeader(context, message, channel), + SizedBox(height: 8), + if (message.content != null) ..._buildMessageContent(context, message), + SizedBox(height: 8), + if (message.senderName != null) UI.metaCard( context: context, - icon: FontAwesomeIcons.solidGearCode, - title: 'KeyToken', - values: [message.usedKeyID, token?.name ?? '...'], + icon: FontAwesomeIcons.solidSignature, + title: 'Sender', + values: [message.senderName!], mainAction: () => { - Navi.push(context, () => FilteredMessageViewPage(title: token?.name ?? message.usedKeyID, filter: MessageFilter(usedKeys: [message.usedKeyID]))) + Navi.push(context, () => FilteredMessageViewPage(title: message.senderName!, filter: MessageFilter(senderNames: [message.senderName!]))) }, ), - UI.metaCard( - context: context, - icon: FontAwesomeIcons.solidIdCardClip, - title: 'MessageID', - values: [message.messageID, message.userMessageID ?? ''], - ), - UI.metaCard( - context: context, - icon: FontAwesomeIcons.solidSnake, - title: 'Channel', - values: [message.channelID, channel?.displayName ?? message.channelInternalName], - mainAction: (channel != null) - ? () { - Navi.push(context, () => ChannelViewPage(channelID: channel.channelID, preloadedData: null, needsReload: null)); - } - : null, - ), - UI.metaCard( - context: context, - icon: FontAwesomeIcons.solidTimer, - title: 'Timestamp', - values: [message.timestamp], - ), - UI.metaCard( - context: context, - icon: FontAwesomeIcons.solidUser, - title: 'User', - values: [user?.userID ?? '...', user?.username ?? ''], - mainAction: () => {/*TODO*/}, - ), - UI.metaCard( - context: context, - icon: FontAwesomeIcons.solidBolt, - title: 'Priority', - values: [_prettyPrintPriority(message.priority)], - mainAction: () => {/*TODO*/}, - ), - if (message.senderUserID == userAccUserID) UI.button(text: "Delete Message", onPressed: () {/*TODO*/}, color: Colors.red[900]), - ], - ), + UI.metaCard( + context: context, + icon: FontAwesomeIcons.solidGearCode, + title: 'KeyToken', + values: [message.usedKeyID, token?.name ?? '...'], + mainAction: () => { + Navi.push(context, () => FilteredMessageViewPage(title: token?.name ?? message.usedKeyID, filter: MessageFilter(usedKeys: [message.usedKeyID]))) + }, + ), + UI.metaCard( + context: context, + icon: FontAwesomeIcons.solidIdCardClip, + title: 'MessageID', + values: [message.messageID, message.userMessageID ?? ''], + ), + UI.metaCard( + context: context, + icon: FontAwesomeIcons.solidSnake, + title: 'Channel', + values: [message.channelID, channel?.displayName ?? message.channelInternalName], + mainAction: (channel != null) + ? () { + Navi.push(context, () => ChannelViewPage(channelID: channel.channelID, preloadedData: null, needsReload: null)); + } + : null, + ), + UI.metaCard( + context: context, + icon: FontAwesomeIcons.solidTimer, + title: 'Timestamp', + values: [message.timestamp], + ), + UI.metaCard( + context: context, + icon: FontAwesomeIcons.solidUser, + title: 'User', + values: [user?.userID ?? '...', user?.username ?? ''], + mainAction: () => {/*TODO*/}, + ), + UI.metaCard( + context: context, + icon: FontAwesomeIcons.solidBolt, + title: 'Priority', + values: [_prettyPrintPriority(message.priority)], + mainAction: () => {/*TODO*/}, + ), + if (message.senderUserID == userAccUserID) UI.button(text: "Delete Message", onPressed: () {/*TODO*/}, color: Colors.red[900]), + ], ), ); + + var showScrollbar = true; + if (!_monospaceMode && (message.content ?? '').length > 4096) showScrollbar = true; + if (_monospaceMode && (message.content ?? '').split('\n').length > 64) showScrollbar = true; + + if (showScrollbar) { + return Padding( + padding: const EdgeInsets.fromLTRB(0, 0, 6, 0), + child: Scrollbar( + thickness: 12.0, + radius: Radius.circular(6), + thumbVisibility: false, + interactive: true, + controller: _controller, + child: SingleChildScrollView( + controller: _controller, + child: child, + ), + ), + ); + } else { + return SingleChildScrollView( + child: child, + ); + } } String _resolveChannelName(ChannelPreview? channel, SCNMessage message) { diff --git a/scnserver/website/js/logic.js b/scnserver/website/js/logic.js index 075c1ed..1bf0ae8 100644 --- a/scnserver/website/js/logic.js +++ b/scnserver/website/js/logic.js @@ -35,7 +35,7 @@ function send() if (xhr.readyState !== 4) return; console.log('Status: ' + xhr.status); - if (xhr.status === 200 || xhr.status === 401 || xhr.status === 403 || xhr.status === 412) + if (xhr.status === 200 || xhr.status === 400 || xhr.status === 401 || xhr.status === 403 || xhr.status === 412) { let resp = JSON.parse(xhr.responseText); if (!resp.success || xhr.status !== 200)