Compare commits

..
4 Commits
Author SHA1 Message Date
Mikescher bb34f3b2b4 Flutter Fixes etc
Build Docker and Deploy / Build Docker Container (push) Successful in 1m7s
Build Docker and Deploy / Run Unit-Tests (push) Failing after 7m34s
Build Docker and Deploy / Deploy to Server (push) Has been skipped
2026-05-31 04:13:13 +02:00
Mikescher 0b7be0908d Upgrade flutter deps 2026-05-31 03:31:02 +02:00
Mikescher 55dc937385 Fix missing links in channel-list
Build Docker and Deploy / Build Docker Container (push) Successful in 2m2s
Build Docker and Deploy / Run Unit-Tests (push) Successful in 7m42s
Build Docker and Deploy / Deploy to Server (push) Successful in 21s
2026-04-08 13:31:23 +02:00
Mikescher e98a804efc Fix panic in /preview/channel/{id}
Build Docker and Deploy / Build Docker Container (push) Successful in 1m49s
Build Docker and Deploy / Run Unit-Tests (push) Successful in 7m56s
Build Docker and Deploy / Deploy to Server (push) Successful in 39s
2026-03-27 12:57:19 +01:00
21 changed files with 13926 additions and 14008 deletions
File diff suppressed because it is too large Load Diff
@@ -1,85 +1,12 @@
library font_awesome_flutter; library font_awesome_flutter;
import 'package:flutter/widgets.dart'; // NOTE:
// This file previously declared IconDataBrands / IconDataSolid / IconDataRegular
/// [IconData] for a font awesome brand icon from a code point // / IconDataLight / IconDataThin / IconDataDuotone as subclasses of [IconData].
/// // Newer Flutter SDKs mark [IconData] as a `final class`, which can no longer be
/// Code points can be obtained from fontawesome.com // extended outside its own library, so those subclasses no longer compile.
class IconDataBrands extends IconData { //
const IconDataBrands(int codePoint) // The generated icon constants in `font_awesome_flutter.dart` now construct
: super( // plain `const IconData(..., fontFamily: '<FontAwesome...>', fontPackage:
codePoint, // 'font_awesome_flutter')` directly, so these helper subclasses are no longer
fontFamily: 'FontAwesomeBrands', // needed. Using const [IconData] literals also keeps icon tree-shaking working.
fontPackage: 'font_awesome_flutter',
);
}
/// [IconData] for a font awesome solid icon from a code point
///
/// Code points can be obtained from fontawesome.com
class IconDataSolid extends IconData {
const IconDataSolid(int codePoint)
: super(
codePoint,
fontFamily: 'FontAwesomeSolid',
fontPackage: 'font_awesome_flutter',
);
}
/// [IconData] for a font awesome regular icon from a code point
///
/// Code points can be obtained from fontawesome.com
class IconDataRegular extends IconData {
const IconDataRegular(int codePoint)
: super(
codePoint,
fontFamily: 'FontAwesomeRegular',
fontPackage: 'font_awesome_flutter',
);
}
/// [IconData] for a font awesome light icon from a code point. Only works if
/// light icons (font awesome pro) have been installed.
///
/// Code points can be obtained from fontawesome.com
class IconDataLight extends IconData {
const IconDataLight(int codePoint)
: super(
codePoint,
fontFamily: 'FontAwesomeLight',
fontPackage: 'font_awesome_flutter',
);
}
/// [IconData] for a font awesome duotone icon from a code point. Only works if
/// duotone icons (font awesome pro) have been installed.
///
/// Code points can be obtained from fontawesome.com. Each duotone icon consists
/// of a primary [codePoint] and a [secondary].
class IconDataDuotone extends IconData {
/// Secondary glyph of the duotone icon
///
/// Due to tree-shaking restraints [secondary] cannot be the codepoint itself,
/// but has to be an [IconData] object.
final IconData? secondary;
const IconDataDuotone(int codePoint, {this.secondary})
: super(
codePoint,
fontFamily: 'FontAwesomeDuotone',
fontPackage: 'font_awesome_flutter',
);
}
/// [IconData] for a font awesome thin icon from a code point. Only works if
/// thin icons (font awesome pro, v6+) have been installed.
///
/// Code points can be obtained from fontawesome.com
class IconDataThin extends IconData {
const IconDataThin(int codePoint)
: super(
codePoint,
fontFamily: 'FontAwesomeThin',
fontPackage: 'font_awesome_flutter',
);
}
@@ -98,7 +98,7 @@ class _SCNNavLayoutState extends State<SCNNavLayout> {
selectedIndex: _selectedIndex, selectedIndex: _selectedIndex,
onTabSelected: _onItemTapped, onTabSelected: _onItemTapped,
color: Theme.of(context).disabledColor, color: Theme.of(context).disabledColor,
selectedColor: Theme.of(context).primaryColorDark, selectedColor: Theme.of(context).colorScheme.primary,
notchedShape: const AutomaticNotchedShape( notchedShape: const AutomaticNotchedShape(
RoundedRectangleBorder( RoundedRectangleBorder(
borderRadius: BorderRadius.only( borderRadius: BorderRadius.only(
+1 -1
View File
@@ -31,7 +31,7 @@ class SCNScaffold extends StatelessWidget {
showShare: showShare, showShare: showShare,
onShare: onShare ?? () {}, onShare: onShare ?? () {},
), ),
body: child, body: SafeArea(child: child),
floatingActionButton: floatingActionButton, floatingActionButton: floatingActionButton,
); );
} }
-1
View File
@@ -132,7 +132,6 @@ void main() async {
requestAlertPermission: true, requestAlertPermission: true,
requestBadgePermission: true, requestBadgePermission: true,
requestSoundPermission: true, requestSoundPermission: true,
onDidReceiveLocalNotification: receiveLocalDarwinNotification,
notificationCategories: getDarwinNotificationCategories(), notificationCategories: getDarwinNotificationCategories(),
); );
final initializationSettingsLinux = LinuxInitializationSettings(defaultActionName: 'Open notification'); final initializationSettingsLinux = LinuxInitializationSettings(defaultActionName: 'Open notification');
-5
View File
@@ -107,11 +107,6 @@ Future<void> _receiveMessage(RemoteMessage message, bool foreground) async {
} }
} }
void receiveLocalDarwinNotification(int id, String? title, String? body, String? payload) {
//TODO iOS?
ApplicationLog.info('Received local notification<darwin>: $id -> [$title]');
}
void receiveLocalNotification(NotificationResponse details) { void receiveLocalNotification(NotificationResponse details) {
// User has tapped a flutter_local notification, while the app was running // User has tapped a flutter_local notification, while the app was running
ApplicationLog.info('Tapped local notification: [[${details.id} | ${details.actionId} | ${details.input} | ${details.notificationResponseType} | ${details.payload}]]'); ApplicationLog.info('Tapped local notification: [[${details.id} | ${details.actionId} | ${details.input} | ${details.notificationResponseType} | ${details.payload}]]');
@@ -69,6 +69,11 @@ class _ChannelListItemState extends State<ChannelListItem> {
margin: EdgeInsets.fromLTRB(0, 4, 0, 4), margin: EdgeInsets.fromLTRB(0, 4, 0, 4),
shape: BeveledRectangleBorder(borderRadius: BorderRadius.circular(0)), shape: BeveledRectangleBorder(borderRadius: BorderRadius.circular(0)),
color: Theme.of(context).cardTheme.color, color: Theme.of(context).cardTheme.color,
child: IntrinsicHeight(
child: Row(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Expanded(
child: InkWell( child: InkWell(
onTap: () { onTap: () {
if (widget.mode == ChannelListItemMode.Messages) { if (widget.mode == ChannelListItemMode.Messages) {
@@ -112,8 +117,13 @@ class _ChannelListItemState extends State<ChannelListItem> {
], ],
), ),
), ),
SizedBox(width: 4), ],
),
),
),
),
GestureDetector( GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () { onTap: () {
if (widget.mode == ChannelListItemMode.Messages) { if (widget.mode == ChannelListItemMode.Messages) {
Navi.push(context, () => ChannelViewPage(channelID: widget.channel.channelID, preloadedData: (widget.channel, widget.subscription), needsReload: widget.onChannelListReloadTrigger)); Navi.push(context, () => ChannelViewPage(channelID: widget.channel.channelID, preloadedData: (widget.channel, widget.subscription), needsReload: widget.onChannelListReloadTrigger));
@@ -122,14 +132,13 @@ class _ChannelListItemState extends State<ChannelListItem> {
} }
}, },
child: Padding( child: Padding(
padding: const EdgeInsets.all(8), padding: const EdgeInsets.only(left: 12, right: 16),
child: (widget.mode == ChannelListItemMode.Messages) ? Icon(FontAwesomeIcons.solidSquareInfo, color: Theme.of(context).colorScheme.onPrimaryContainer.withAlpha(128), size: 24) : Icon(FontAwesomeIcons.solidEnvelopes, color: Theme.of(context).colorScheme.onPrimaryContainer.withAlpha(128), size: 24), child: Center(widthFactor: 1.0, child: (widget.mode == ChannelListItemMode.Messages) ? Icon(FontAwesomeIcons.solidSquareInfo, color: Theme.of(context).colorScheme.onPrimaryContainer.withAlpha(128), size: 24) : Icon(FontAwesomeIcons.solidEnvelopes, color: Theme.of(context).colorScheme.onPrimaryContainer.withAlpha(128), size: 24)),
), ),
), ),
], ],
), ),
), ),
),
); );
} }
@@ -31,6 +31,11 @@ class KeyTokenListItem extends StatelessWidget {
margin: EdgeInsets.fromLTRB(0, 4, 0, 4), margin: EdgeInsets.fromLTRB(0, 4, 0, 4),
shape: BeveledRectangleBorder(borderRadius: BorderRadius.circular(0)), shape: BeveledRectangleBorder(borderRadius: BorderRadius.circular(0)),
color: Theme.of(context).cardTheme.color, color: Theme.of(context).cardTheme.color,
child: IntrinsicHeight(
child: Row(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Expanded(
child: InkWell( child: InkWell(
onTap: () { onTap: () {
Navi.push(context, () => KeyTokenViewPage(keytokenID: item.keytokenID, preloadedData: item, needsReload: needsReload)); Navi.push(context, () => KeyTokenViewPage(keytokenID: item.keytokenID, preloadedData: item, needsReload: needsReload));
@@ -75,20 +80,24 @@ class KeyTokenListItem extends StatelessWidget {
], ],
), ),
), ),
SizedBox(width: 4), ],
),
),
),
),
GestureDetector( GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () { onTap: () {
Navi.push(context, () => FilteredMessageViewPage(title: item.name, alertText: 'All message sent with the key \'${item.name}\'', filter: MessageFilter(usedKeys: [item.keytokenID]))); Navi.push(context, () => FilteredMessageViewPage(title: item.name, alertText: 'All message sent with the key \'${item.name}\'', filter: MessageFilter(usedKeys: [item.keytokenID])));
}, },
child: Padding( child: Padding(
padding: const EdgeInsets.all(8), padding: const EdgeInsets.only(left: 12, right: 16),
child: Icon(FontAwesomeIcons.solidEnvelopes, color: Theme.of(context).colorScheme.onPrimaryContainer.withAlpha(128), size: 24), child: Center(widthFactor: 1.0, child: Icon(FontAwesomeIcons.solidEnvelopes, color: Theme.of(context).colorScheme.onPrimaryContainer.withAlpha(128), size: 24)),
), ),
), ),
], ],
), ),
), ),
),
); );
} }
@@ -28,9 +28,14 @@ class SenderListItem extends StatelessWidget {
margin: EdgeInsets.fromLTRB(0, 4, 0, 4), margin: EdgeInsets.fromLTRB(0, 4, 0, 4),
shape: BeveledRectangleBorder(borderRadius: BorderRadius.circular(0)), shape: BeveledRectangleBorder(borderRadius: BorderRadius.circular(0)),
color: Theme.of(context).cardTheme.color, color: Theme.of(context).cardTheme.color,
child: IntrinsicHeight(
child: Row(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Expanded(
child: InkWell( child: InkWell(
onTap: () { onTap: () {
Navi.push(context, () => FilteredMessageViewPage(title: item.name, alertText: 'All message sent from \'${item.name!}\'', filter: MessageFilter(senderNames: [item.name]))); Navi.push(context, () => FilteredMessageViewPage(title: item.name, alertText: 'All message sent from \'${item.name}\'', filter: MessageFilter(senderNames: [item.name])));
}, },
child: Padding( child: Padding(
padding: const EdgeInsets.all(8), padding: const EdgeInsets.all(8),
@@ -68,20 +73,24 @@ class SenderListItem extends StatelessWidget {
], ],
), ),
), ),
SizedBox(width: 4), ],
),
),
),
),
GestureDetector( GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () { onTap: () {
Navi.push(context, () => FilteredMessageViewPage(title: item.name, alertText: 'All message sent from \'${item.name!}\'', filter: MessageFilter(senderNames: [item.name]))); Navi.push(context, () => FilteredMessageViewPage(title: item.name, alertText: 'All message sent from \'${item.name}\'', filter: MessageFilter(senderNames: [item.name])));
}, },
child: Padding( child: Padding(
padding: const EdgeInsets.all(8), padding: const EdgeInsets.only(left: 12, right: 16),
child: Icon(FontAwesomeIcons.solidEnvelopes, color: Theme.of(context).colorScheme.onPrimaryContainer.withAlpha(128), size: 24), child: Center(widthFactor: 1.0, child: Icon(FontAwesomeIcons.solidEnvelopes, color: Theme.of(context).colorScheme.onPrimaryContainer.withAlpha(128), size: 24)),
), ),
), ),
], ],
), ),
), ),
),
); );
} }
} }
+72 -72
View File
@@ -149,10 +149,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: characters name: characters
sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 sha256: faf38497bda5ead2a8c7615f4f7939df04333478bf32e4173fcb06d428b5716b
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.4.0" version: "1.4.1"
checked_yaml: checked_yaml:
dependency: transitive dependency: transitive
description: description:
@@ -205,10 +205,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: cross_file name: cross_file
sha256: "942a4791cd385a68ccb3b32c71c427aba508a1bb949b86dff2adbe4049f16239" sha256: "28bb3ae56f117b5aec029d702a90f57d285cd975c3c5c281eaca38dbc47c5937"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.3.5" version: "0.3.5+2"
crypto: crypto:
dependency: transitive dependency: transitive
description: description:
@@ -221,10 +221,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: cupertino_icons name: cupertino_icons
sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6 sha256: "41e005c33bd814be4d3096aff55b1908d419fde52ca656c8c47719ec745873cd"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.8" version: "1.0.9"
dart_style: dart_style:
dependency: transitive dependency: transitive
description: description:
@@ -245,18 +245,18 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: device_info_plus name: device_info_plus
sha256: "98f28b42168cc509abc92f88518882fd58061ea372d7999aecc424345c7bff6a" sha256: "6a642e1daa10190af89ba6cb6386c0df7d071a3592080bfe1e44faa63ae1df65"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "11.5.0" version: "13.1.0"
device_info_plus_platform_interface: device_info_plus_platform_interface:
dependency: transitive dependency: transitive
description: description:
name: device_info_plus_platform_interface name: device_info_plus_platform_interface
sha256: e1ea89119e34903dca74b883d0dd78eb762814f97fb6c76f35e9ff74d261a18f sha256: "04b173a92e2d9161dfead145667037c8d834db725ce2e7b942bfe18fd2f45a46"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "7.0.3" version: "8.1.0"
encrypt: encrypt:
dependency: transitive dependency: transitive
description: description:
@@ -285,10 +285,18 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: ffi name: ffi
sha256: "289279317b4b16eb2bb7e271abccd4bf84ec9bdcbe999e278a94b804f5630418" sha256: "6d7fd89431262d8f3125e81b50d3847a091d846eafcd4fdb88dd06f36d705a45"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.4" version: "2.2.0"
ffi_leak_tracker:
dependency: transitive
description:
name: ffi_leak_tracker
sha256: "4093d4ef9ca06ffe2786e73bfb25e22aa92112b9bb4ec941f11e3e6b61489a97"
url: "https://pub.dev"
source: hosted
version: "0.1.2"
file: file:
dependency: transitive dependency: transitive
description: description:
@@ -378,42 +386,42 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: flutter_lazy_indexed_stack name: flutter_lazy_indexed_stack
sha256: "3e905c0f130538f686e4e07bb8d0bc0dee6890366c65da199fb356aab52e0bff" sha256: e5a6c061a336dcb6f6758d63c7d3d40698a4581e766da6de00ed2b8822b15199
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.0.7" version: "0.1.0"
flutter_lints: flutter_lints:
dependency: "direct dev" dependency: "direct dev"
description: description:
name: flutter_lints name: flutter_lints
sha256: "5398f14efa795ffb7a33e9b6a08798b26a180edac4ad7db3f231e40f82ce11e1" sha256: "3105dc8492f6183fb076ccf1f351ac3d60564bff92e20bfc4af9cc1651f4e7e1"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "5.0.0" version: "6.0.0"
flutter_local_notifications: flutter_local_notifications:
dependency: "direct main" dependency: "direct main"
description: description:
name: flutter_local_notifications name: flutter_local_notifications
sha256: "674173fd3c9eda9d4c8528da2ce0ea69f161577495a9cc835a2a4ecd7eadeb35" sha256: ef41ae901e7529e52934feba19ed82827b11baa67336829564aeab3129460610
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "17.2.4" version: "18.0.1"
flutter_local_notifications_linux: flutter_local_notifications_linux:
dependency: transitive dependency: transitive
description: description:
name: flutter_local_notifications_linux name: flutter_local_notifications_linux
sha256: c49bd06165cad9beeb79090b18cd1eb0296f4bf4b23b84426e37dd7c027fc3af sha256: "8f685642876742c941b29c32030f6f4f6dacd0e4eaecb3efbb187d6a3812ca01"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "4.0.1" version: "5.0.0"
flutter_local_notifications_platform_interface: flutter_local_notifications_platform_interface:
dependency: transitive dependency: transitive
description: description:
name: flutter_local_notifications_platform_interface name: flutter_local_notifications_platform_interface
sha256: "85f8d07fe708c1bdcf45037f2c0109753b26ae077e9d9e899d55971711a4ea66" sha256: "6c5b83c86bf819cdb177a9247a3722067dd8cc6313827ce7c77a4b238a26fd52"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "7.2.0" version: "8.0.0"
flutter_staggered_grid_view: flutter_staggered_grid_view:
dependency: transitive dependency: transitive
description: description:
@@ -499,10 +507,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: http name: http
sha256: bb2ce4590bc2667c96f318d68cac1b5a7987ec819351d32b1c987239a815e007 sha256: "87721a4a50b19c7f1d49001e51409bddc46303966ce89a65af4f4e6004896412"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.5.0" version: "1.6.0"
http_multi_server: http_multi_server:
dependency: transitive dependency: transitive
description: description:
@@ -519,14 +527,6 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "4.1.2" version: "4.1.2"
iconsax_flutter:
dependency: transitive
description:
name: iconsax_flutter
sha256: d14b4cec8586025ac15276bdd40f6eea308cb85748135965bb6255f14beb2564
url: "https://pub.dev"
source: hosted
version: "1.0.1"
image: image:
dependency: transitive dependency: transitive
description: description:
@@ -635,10 +635,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: lints name: lints
sha256: c35bb79562d980e9a453fc715854e1ed39e24e7d0297a880ef54e17f9874a9d7 sha256: "12f842a479589fea194fe5c5a3095abc7be0c1f2ddfa9a0e76aed1dbd26a87df"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "5.1.1" version: "6.1.0"
logging: logging:
dependency: transitive dependency: transitive
description: description:
@@ -651,26 +651,26 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: matcher name: matcher
sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 sha256: dc0b7dc7651697ea4ff3e69ef44b0407ea32c487a39fff6a4004fa585e901861
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.12.17" version: "0.12.19"
material_color_utilities: material_color_utilities:
dependency: transitive dependency: transitive
description: description:
name: material_color_utilities name: material_color_utilities
sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec sha256: "9c337007e82b1889149c82ed242ed1cb24a66044e30979c44912381e9be4c48b"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.11.1" version: "0.13.0"
meta: meta:
dependency: transitive dependency: transitive
description: description:
name: meta name: meta
sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c sha256: "1741988757a65eb6b36abe716829688cf01910bbf91c34354ff7ec1c3de2b349"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.16.0" version: "1.18.0"
mime: mime:
dependency: transitive dependency: transitive
description: description:
@@ -683,10 +683,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: mobile_scanner name: mobile_scanner
sha256: "0b466a0a8a211b366c2e87f3345715faef9b6011c7147556ad22f37de6ba3173" sha256: c92c26bf2231695b6d3477c8dcf435f51e28f87b1745966b1fe4c47a286171ce
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "6.0.11" version: "7.2.0"
mutex: mutex:
dependency: "direct main" dependency: "direct main"
description: description:
@@ -715,18 +715,18 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: package_info_plus name: package_info_plus
sha256: "16eee997588c60225bda0488b6dcfac69280a6b7a3cf02c741895dd370a02968" sha256: "4bf625947f6c7713ee242296a682e23e44823c09cf9d79e4f1238923c92db852"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "8.3.1" version: "10.1.0"
package_info_plus_platform_interface: package_info_plus_platform_interface:
dependency: transitive dependency: transitive
description: description:
name: package_info_plus_platform_interface name: package_info_plus_platform_interface
sha256: "202a487f08836a592a6bd4f901ac69b3a8f146af552bbd14407b6b41e1c3f086" sha256: db762cb2f4f25ee60fb6359773861b0f199e00b90d237bd85a76a1e806b46ef4
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.2.1" version: "4.1.0"
path: path:
dependency: "direct main" dependency: "direct main"
description: description:
@@ -883,34 +883,34 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: settings_ui name: settings_ui
sha256: d9838037cb554b24b4218b2d07666fbada3478882edefae375ee892b6c820ef3 sha256: "7437c9c867f331ff6c90e951f2333441eab5cf5e654c3a7f3e4aad0c01db51ef"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.2" version: "3.0.1"
share_plus: share_plus:
dependency: "direct main" dependency: "direct main"
description: description:
name: share_plus name: share_plus
sha256: fce43200aa03ea87b91ce4c3ac79f0cecd52e2a7a56c7a4185023c271fbfa6da sha256: a857d8b1479250aff6b57a51b2c02d31ca05848d441817c43f1640c885c286c0
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "10.1.4" version: "13.1.0"
share_plus_platform_interface: share_plus_platform_interface:
dependency: transitive dependency: transitive
description: description:
name: share_plus_platform_interface name: share_plus_platform_interface
sha256: cc012a23fc2d479854e6c80150696c4a5f5bb62cb89af4de1c505cf78d0a5d0b sha256: "7f7ae28cf400d13f811e297ff37742dba83b79e0a6f5dce14eec0248274e6ce9"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "5.0.2" version: "7.1.0"
shared_preferences: shared_preferences:
dependency: "direct main" dependency: "direct main"
description: description:
name: shared_preferences name: shared_preferences
sha256: "6e8bf70b7fef813df4e9a36f658ac46d107db4b4cfe1048b477d4e453a8159f5" sha256: c3025c5534b01739267eb7d76959bbc25a6d10f6988e1c2a3036940133dd10bf
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.5.3" version: "2.5.5"
shared_preferences_android: shared_preferences_android:
dependency: transitive dependency: transitive
description: description:
@@ -1056,10 +1056,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: test_api name: test_api
sha256: "522f00f556e73044315fa4585ec3270f1808a4b186c936e612cab0b565ff1e00" sha256: "949a932224383300f01be9221c39180316445ecb8e7547f70a41a35bf421fb9e"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.7.6" version: "0.7.11"
timezone: timezone:
dependency: transitive dependency: transitive
description: description:
@@ -1080,10 +1080,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: toastification name: toastification
sha256: "69db2bff425b484007409650d8bcd5ed1ce2e9666293ece74dcd917dacf23112" sha256: "66c96678e3dece8ba24de3ea31634bd65a80aaecb8105f9bafe946e5f0d7590a"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.0.3" version: "3.2.0"
typed_data: typed_data:
dependency: transitive dependency: transitive
description: description:
@@ -1120,10 +1120,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: url_launcher_linux name: url_launcher_linux
sha256: "4e9ba368772369e3e08f231d2301b4ef72b9ff87c31192ef471b380ef29a4935" sha256: d5e14138b3bc193a0f63c10a53c94b91d399df0512b1f29b94a043db7482384a
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.2.1" version: "3.2.2"
url_launcher_macos: url_launcher_macos:
dependency: transitive dependency: transitive
description: description:
@@ -1144,26 +1144,26 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: url_launcher_web name: url_launcher_web
sha256: "4bd2b7b4dc4d4d0b94e5babfffbca8eac1a126c7f3d6ecbc1a11013faa3abba2" sha256: "85c81589622fbc87c1c683aaea164d3604a7777495a79d91e39ffcdec39ddb34"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.4.1" version: "2.4.3"
url_launcher_windows: url_launcher_windows:
dependency: transitive dependency: transitive
description: description:
name: url_launcher_windows name: url_launcher_windows
sha256: "3284b6d2ac454cf34f114e1d3319866fdd1e19cdc329999057e44ffe936cfa77" sha256: "712c70ab1b99744ff066053cbe3e80c73332b38d46e5e945c98689b2e66fc15f"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.1.4" version: "3.1.5"
uuid: uuid:
dependency: "direct main" dependency: "direct main"
description: description:
name: uuid name: uuid
sha256: a11b666489b1954e01d992f3d601b1804a33937b5a8fe677bd26b8a9f96f96e8 sha256: "1fef9e8e11e2991bb773070d4656b7bd5d850967a2456cfc83cf47925ba79489"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "4.5.2" version: "4.5.3"
vector_math: vector_math:
dependency: transitive dependency: transitive
description: description:
@@ -1216,18 +1216,18 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: win32 name: win32
sha256: d7cb55e04cd34096cd3a79b3330245f54cb96a370a1c27adb3c84b917de8b08e sha256: ba6f4bba816c8d7e3c1580e170f3786d216951cc6b94babc3b814c08d2cb2738
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "5.15.0" version: "6.3.0"
win32_registry: win32_registry:
dependency: transitive dependency: transitive
description: description:
name: win32_registry name: win32_registry
sha256: "6f1b564492d0147b330dd794fee8f512cec4977957f310f9951b5f9d83618dae" sha256: "73b1d78920a9d6e03f8b4e43e612b87bf3152a0e5c5e5150267762b7c4116904"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.0" version: "3.0.3"
xdg_directories: xdg_directories:
dependency: transitive dependency: transitive
description: description:
@@ -1261,5 +1261,5 @@ packages:
source: hosted source: hosted
version: "3.1.3" version: "3.1.3"
sdks: sdks:
dart: ">=3.9.0 <4.0.0" dart: ">=3.10.0 <4.0.0"
flutter: ">=3.35.0" flutter: ">=3.38.1"
+14 -14
View File
@@ -2,7 +2,7 @@ name: simplecloudnotifier
description: "Receive push messages" description: "Receive push messages"
publish_to: 'none' publish_to: 'none'
version: 2.2.2+544 version: 2.2.8+553
environment: environment:
sdk: '>=3.9.0 <4.0.0' sdk: '>=3.9.0 <4.0.0'
@@ -14,31 +14,31 @@ dependencies:
flutter_launcher_icons: ^0.14.3 flutter_launcher_icons: ^0.14.3
font_awesome_flutter: '>= 4.7.0' font_awesome_flutter: '>= 4.7.0'
cupertino_icons: ^1.0.2 cupertino_icons: ^1.0.9
http: ^1.2.0 http: ^1.6.0
provider: ^6.1.1 provider: ^6.1.1
shared_preferences: ^2.2.2 shared_preferences: ^2.5.5
qr_flutter: ^4.1.0 qr_flutter: ^4.1.0
url_launcher: ^6.2.4 url_launcher: ^6.2.4
infinite_scroll_pagination: ^4.0.0 infinite_scroll_pagination: ^4.0.0
intl: ^0.20.2 intl: ^0.20.2
path_provider: ^2.1.3 path_provider: ^2.1.3
hive_flutter: ^1.1.0 hive_flutter: ^1.1.0
package_info_plus: ^8.0.0 package_info_plus: ^10.1.0
xid: ^1.2.1 xid: ^1.2.1
flutter_lazy_indexed_stack: ^0.0.6 flutter_lazy_indexed_stack: ^0.1.0
firebase_core: ^3.13.0 firebase_core: ^3.13.0
firebase_messaging: ^15.2.5 firebase_messaging: ^15.2.5
device_info_plus: ^11.3.0 device_info_plus: ^13.1.0
toastification: ^3.0.1 toastification: ^3.2.0
uuid: ^4.4.0 uuid: ^4.5.3
share_plus: ^10.1.4 share_plus: ^13.1.0
flutter_local_notifications: ^17.2.3 flutter_local_notifications: ^18.0.0
path: any path: any
mobile_scanner: ^6.0.1 mobile_scanner: ^7.2.0
settings_ui: ^2.0.2 settings_ui: ^3.0.1
git_stamp: ^5.10.0 git_stamp: ^5.10.0
action_slider: ^0.7.0 action_slider: ^0.7.0
mutex: ^3.1.0 mutex: ^3.1.0
@@ -52,7 +52,7 @@ dev_dependencies:
flutter_test: flutter_test:
sdk: flutter sdk: flutter
flutter_lints: ^5.0.0 flutter_lints: ^6.0.0
hive_generator: ^2.0.1 hive_generator: ^2.0.1
build_runner: ^2.1.4 build_runner: ^2.1.4
+12 -12
View File
@@ -93,13 +93,13 @@ func (h APIHandler) GetChannelPreview(pctx ginext.PreContext) ginext.HTTPRespons
userid := *ctx.GetPermissionUserID() userid := *ctx.GetPermissionUserID()
channel, err := h.database.GetChannelByID(ctx, u.ChannelID) channel, err := h.database.GetChannelByIDOpt(ctx, u.ChannelID)
if errors.Is(err, sql.ErrNoRows) {
return ginresp.APIError(g, 404, apierr.CHANNEL_NOT_FOUND, "Channel not found", err)
}
if err != nil { if err != nil {
return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to query channel", err) return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to query channel", err)
} }
if channel == nil {
return ginresp.APIError(g, 404, apierr.CHANNEL_NOT_FOUND, "Channel not found", err)
}
sub, err := h.database.GetSubscriptionBySubscriber(ctx, userid, channel.ChannelID) sub, err := h.database.GetSubscriptionBySubscriber(ctx, userid, channel.ChannelID)
if err != nil { if err != nil {
@@ -162,13 +162,13 @@ func (h APIHandler) GetUserKeyPreview(pctx ginext.PreContext) ginext.HTTPRespons
// Query by token.token // Query by token.token
keytoken, err := h.database.GetKeyTokenByToken(ctx, u.KeyID) keytoken, err := h.database.GetKeyTokenByTokenOpt(ctx, u.KeyID)
if keytoken == nil {
return ginresp.APIError(g, 404, apierr.KEY_NOT_FOUND, "Key not found", err)
}
if err != nil { if err != nil {
return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to query client", err) return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to query client", err)
} }
if keytoken == nil {
return ginresp.APIError(g, 404, apierr.KEY_NOT_FOUND, "Key not found", err)
}
return finishSuccess(ginext.JSON(http.StatusOK, keytoken.Preview())) return finishSuccess(ginext.JSON(http.StatusOK, keytoken.Preview()))
@@ -215,13 +215,13 @@ func (h APIHandler) GetClientPreview(pctx ginext.PreContext) ginext.HTTPResponse
return *permResp return *permResp
} }
client, err := h.database.GetClientByID(ctx, u.ClientID) client, err := h.database.GetClientByIDOpt(ctx, u.ClientID)
if client == nil {
return ginresp.APIError(g, 404, apierr.CLIENT_NOT_FOUND, "Client not found", err)
}
if err != nil { if err != nil {
return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to query client", err) return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to query client", err)
} }
if client == nil {
return ginresp.APIError(g, 404, apierr.CLIENT_NOT_FOUND, "Client not found", err)
}
user, err := h.database.GetUser(ctx, client.UserID) user, err := h.database.GetUser(ctx, client.UserID)
if errors.Is(err, sql.ErrNoRows) { if errors.Is(err, sql.ErrNoRows) {
+1 -1
View File
@@ -362,7 +362,7 @@ func (h APIHandler) CreateSubscription(pctx ginext.PreContext) ginext.HTTPRespon
} else if b.ChannelOwnerUserID == nil && b.ChannelInternalName == nil && b.ChannelID != nil { } else if b.ChannelOwnerUserID == nil && b.ChannelInternalName == nil && b.ChannelID != nil {
outchannel, err := h.database.GetChannelByID(ctx, *b.ChannelID) outchannel, err := h.database.GetChannelByIDOpt(ctx, *b.ChannelID)
if err != nil { if err != nil {
return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to query channel", err) return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to query channel", err)
} }
+6 -6
View File
@@ -305,7 +305,7 @@ func (h CompatHandler) Info(pctx ginext.PreContext) ginext.HTTPResponse {
return ginresp.CompatAPIError(0, "Failed to query user") return ginresp.CompatAPIError(0, "Failed to query user")
} }
keytok, err := h.database.GetKeyTokenByToken(ctx, *data.UserKey) keytok, err := h.database.GetKeyTokenByTokenOpt(ctx, *data.UserKey)
if err != nil { if err != nil {
return ginresp.CompatAPIError(0, "Failed to query token") return ginresp.CompatAPIError(0, "Failed to query token")
} }
@@ -417,7 +417,7 @@ func (h CompatHandler) Ack(pctx ginext.PreContext) ginext.HTTPResponse {
return ginresp.CompatAPIError(0, "Failed to query user") return ginresp.CompatAPIError(0, "Failed to query user")
} }
keytok, err := h.database.GetKeyTokenByToken(ctx, *data.UserKey) keytok, err := h.database.GetKeyTokenByTokenOpt(ctx, *data.UserKey)
if err != nil { if err != nil {
return ginresp.CompatAPIError(0, "Failed to query token") return ginresp.CompatAPIError(0, "Failed to query token")
} }
@@ -523,7 +523,7 @@ func (h CompatHandler) Requery(pctx ginext.PreContext) ginext.HTTPResponse {
return ginresp.CompatAPIError(0, "Failed to query user") return ginresp.CompatAPIError(0, "Failed to query user")
} }
keytok, err := h.database.GetKeyTokenByToken(ctx, *data.UserKey) keytok, err := h.database.GetKeyTokenByTokenOpt(ctx, *data.UserKey)
if err != nil { if err != nil {
return ginresp.CompatAPIError(0, "Failed to query token") return ginresp.CompatAPIError(0, "Failed to query token")
} }
@@ -644,7 +644,7 @@ func (h CompatHandler) Update(pctx ginext.PreContext) ginext.HTTPResponse {
return ginresp.CompatAPIError(0, "Failed to query user") return ginresp.CompatAPIError(0, "Failed to query user")
} }
keytok, err := h.database.GetKeyTokenByToken(ctx, *data.UserKey) keytok, err := h.database.GetKeyTokenByTokenOpt(ctx, *data.UserKey)
if err != nil { if err != nil {
return ginresp.CompatAPIError(0, "Failed to query token") return ginresp.CompatAPIError(0, "Failed to query token")
} }
@@ -778,7 +778,7 @@ func (h CompatHandler) Expand(pctx ginext.PreContext) ginext.HTTPResponse {
return ginresp.CompatAPIError(0, "Failed to query user") return ginresp.CompatAPIError(0, "Failed to query user")
} }
keytok, err := h.database.GetKeyTokenByToken(ctx, *data.UserKey) keytok, err := h.database.GetKeyTokenByTokenOpt(ctx, *data.UserKey)
if err != nil { if err != nil {
return ginresp.CompatAPIError(0, "Failed to query token") return ginresp.CompatAPIError(0, "Failed to query token")
} }
@@ -901,7 +901,7 @@ func (h CompatHandler) Upgrade(pctx ginext.PreContext) ginext.HTTPResponse {
return ginresp.CompatAPIError(0, "Failed to query user") return ginresp.CompatAPIError(0, "Failed to query user")
} }
keytok, err := h.database.GetKeyTokenByToken(ctx, *data.UserKey) keytok, err := h.database.GetKeyTokenByTokenOpt(ctx, *data.UserKey)
if err != nil { if err != nil {
return ginresp.CompatAPIError(0, "Failed to query token") return ginresp.CompatAPIError(0, "Failed to query token")
} }
+3 -2
View File
@@ -1,10 +1,11 @@
package primary package primary
import ( import (
"time"
"blackforestbytes.com/simplecloudnotifier/db" "blackforestbytes.com/simplecloudnotifier/db"
"blackforestbytes.com/simplecloudnotifier/models" "blackforestbytes.com/simplecloudnotifier/models"
"git.blackforestbytes.com/BlackForestBytes/goext/sq" "git.blackforestbytes.com/BlackForestBytes/goext/sq"
"time"
) )
func (db *Database) GetChannelByName(ctx db.TxContext, userid models.UserID, chanName string) (*models.Channel, error) { func (db *Database) GetChannelByName(ctx db.TxContext, userid models.UserID, chanName string) (*models.Channel, error) {
@@ -16,7 +17,7 @@ func (db *Database) GetChannelByName(ctx db.TxContext, userid models.UserID, cha
return sq.QuerySingleOpt[models.Channel](ctx, tx, "SELECT * FROM channels WHERE owner_user_id = :uid AND internal_name = :nam AND deleted=0 LIMIT 1", sq.PP{"uid": userid, "nam": chanName}, sq.SModeExtended, sq.Safe) return sq.QuerySingleOpt[models.Channel](ctx, tx, "SELECT * FROM channels WHERE owner_user_id = :uid AND internal_name = :nam AND deleted=0 LIMIT 1", sq.PP{"uid": userid, "nam": chanName}, sq.SModeExtended, sq.Safe)
} }
func (db *Database) GetChannelByID(ctx db.TxContext, chanid models.ChannelID) (*models.Channel, error) { func (db *Database) GetChannelByIDOpt(ctx db.TxContext, chanid models.ChannelID) (*models.Channel, error) {
tx, err := ctx.GetOrCreateTransaction(db) tx, err := ctx.GetOrCreateTransaction(db)
if err != nil { if err != nil {
return nil, err return nil, err
+1 -1
View File
@@ -53,7 +53,7 @@ func (db *Database) GetClient(ctx db.TxContext, userid models.UserID, clientid m
}, sq.SModeExtended, sq.Safe) }, sq.SModeExtended, sq.Safe)
} }
func (db *Database) GetClientByID(ctx db.TxContext, clientid models.ClientID) (*models.Client, error) { func (db *Database) GetClientByIDOpt(ctx db.TxContext, clientid models.ClientID) (*models.Client, error) {
tx, err := ctx.GetOrCreateTransaction(db) tx, err := ctx.GetOrCreateTransaction(db)
if err != nil { if err != nil {
return nil, err return nil, err
+4 -3
View File
@@ -1,12 +1,13 @@
package primary package primary
import ( import (
"strings"
"time"
"blackforestbytes.com/simplecloudnotifier/db" "blackforestbytes.com/simplecloudnotifier/db"
"blackforestbytes.com/simplecloudnotifier/models" "blackforestbytes.com/simplecloudnotifier/models"
"git.blackforestbytes.com/BlackForestBytes/goext/langext" "git.blackforestbytes.com/BlackForestBytes/goext/langext"
"git.blackforestbytes.com/BlackForestBytes/goext/sq" "git.blackforestbytes.com/BlackForestBytes/goext/sq"
"strings"
"time"
) )
func (db *Database) CreateKeyToken(ctx db.TxContext, name string, owner models.UserID, allChannels bool, channels []models.ChannelID, permissions models.TokenPermissionList, token string) (models.KeyToken, error) { func (db *Database) CreateKeyToken(ctx db.TxContext, name string, owner models.UserID, allChannels bool, channels []models.ChannelID, permissions models.TokenPermissionList, token string) (models.KeyToken, error) {
@@ -67,7 +68,7 @@ func (db *Database) GetKeyTokenByID(ctx db.TxContext, keyTokenid models.KeyToken
return sq.QuerySingle[models.KeyToken](ctx, tx, "SELECT * FROM keytokens WHERE keytoken_id = :cid AND deleted=0 LIMIT 1", sq.PP{"cid": keyTokenid}, sq.SModeExtended, sq.Safe) return sq.QuerySingle[models.KeyToken](ctx, tx, "SELECT * FROM keytokens WHERE keytoken_id = :cid AND deleted=0 LIMIT 1", sq.PP{"cid": keyTokenid}, sq.SModeExtended, sq.Safe)
} }
func (db *Database) GetKeyTokenByToken(ctx db.TxContext, key string) (*models.KeyToken, error) { func (db *Database) GetKeyTokenByTokenOpt(ctx db.TxContext, key string) (*models.KeyToken, error) {
tx, err := ctx.GetOrCreateTransaction(db) tx, err := ctx.GetOrCreateTransaction(db)
if err != nil { if err != nil {
return nil, err return nil, err
+5 -4
View File
@@ -1,14 +1,15 @@
package jobs package jobs
import ( import (
"errors"
"fmt"
"time"
"blackforestbytes.com/simplecloudnotifier/db/simplectx" "blackforestbytes.com/simplecloudnotifier/db/simplectx"
"blackforestbytes.com/simplecloudnotifier/logic" "blackforestbytes.com/simplecloudnotifier/logic"
"blackforestbytes.com/simplecloudnotifier/models" "blackforestbytes.com/simplecloudnotifier/models"
"errors"
"fmt"
"git.blackforestbytes.com/BlackForestBytes/goext/syncext" "git.blackforestbytes.com/BlackForestBytes/goext/syncext"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
"time"
) )
type DeliveryRetryJob struct { type DeliveryRetryJob struct {
@@ -208,7 +209,7 @@ func (j *DeliveryRetryJob) redeliver(ctx *simplectx.SimpleContext, delivery mode
return return
} }
channel, err := j.app.Database.Primary.GetChannelByID(ctx, msg.ChannelID) channel, err := j.app.Database.Primary.GetChannelByIDOpt(ctx, msg.ChannelID)
if err != nil { if err != nil {
log.Err(err).Str("ChannelID", msg.ChannelID.String()).Msg("Failed to get channel") log.Err(err).Str("ChannelID", msg.ChannelID.String()).Msg("Failed to get channel")
ctx.RollbackTransaction() ctx.RollbackTransaction()
+1 -1
View File
@@ -245,7 +245,7 @@ func (app *Application) getPermissions(ctx db.TxContext, hdr string) (models.Per
key := strings.TrimSpace(hdr[4:]) key := strings.TrimSpace(hdr[4:])
tok, err := app.Database.Primary.GetKeyTokenByToken(ctx, key) tok, err := app.Database.Primary.GetKeyTokenByTokenOpt(ctx, key)
if err != nil { if err != nil {
return models.PermissionSet{}, err return models.PermissionSet{}, err
} }
+1 -1
View File
@@ -75,7 +75,7 @@ func (ac *AppContext) CheckPermissionUserAdmin(userid models.UserID) *ginext.HTT
func (ac *AppContext) CheckPermissionSend(channel models.Channel, key string) (*models.KeyToken, *ginext.HTTPResponse) { func (ac *AppContext) CheckPermissionSend(channel models.Channel, key string) (*models.KeyToken, *ginext.HTTPResponse) {
keytok, err := ac.app.Database.Primary.GetKeyTokenByToken(ac, key) keytok, err := ac.app.Database.Primary.GetKeyTokenByTokenOpt(ac, key)
if err != nil { if err != nil {
return nil, langext.Ptr(ginresp.APIError(ac.ginContext, 500, apierr.DATABASE_ERROR, "Failed to query token", err)) return nil, langext.Ptr(ginresp.APIError(ac.ginContext, 500, apierr.DATABASE_ERROR, "Failed to query token", err))
} }
@@ -50,50 +50,30 @@
</thead> </thead>
<tbody> <tbody>
@for (channel of channels(); track channel.channel_id) { @for (channel of channels(); track channel.channel_id) {
<tr [class.clickable-row]="isOwned(channel)"> <tr class="clickable-row">
<td> <td>
@if (isOwned(channel)) {
<a class="cell-link" [routerLink]="['/channels', channel.channel_id]"> <a class="cell-link" [routerLink]="['/channels', channel.channel_id]">
<div class="channel-name">{{ channel.display_name }}</div> <div class="channel-name">{{ channel.display_name }}</div>
<div class="channel-id mono">{{ channel.channel_id }}</div> <div class="channel-id mono">{{ channel.channel_id }}</div>
</a> </a>
} @else {
<div class="channel-name">{{ channel.display_name }}</div>
<div class="channel-id mono">{{ channel.channel_id }}</div>
}
</td> </td>
<td> <td>
@if (isOwned(channel)) {
<a class="cell-link" [routerLink]="['/channels', channel.channel_id]"> <a class="cell-link" [routerLink]="['/channels', channel.channel_id]">
<span class="mono">{{ channel.internal_name }}</span> <span class="mono">{{ channel.internal_name }}</span>
</a> </a>
} @else {
<span class="mono">{{ channel.internal_name }}</span>
}
</td> </td>
<td> <td>
@if (isOwned(channel)) {
<a class="cell-link" [routerLink]="['/channels', channel.channel_id]"> <a class="cell-link" [routerLink]="['/channels', channel.channel_id]">
<div class="channel-name">{{ getOwnerDisplayName(channel.owner_user_id) }}</div> <div class="channel-name">{{ getOwnerDisplayName(channel.owner_user_id) }}</div>
<div class="channel-id mono">{{ channel.owner_user_id }}</div> <div class="channel-id mono">{{ channel.owner_user_id }}</div>
</a> </a>
} @else {
<div class="channel-name">{{ getOwnerDisplayName(channel.owner_user_id) }}</div>
<div class="channel-id mono">{{ channel.owner_user_id }}</div>
}
</td> </td>
<td> <td>
@if (isOwned(channel)) {
<a class="cell-link" [routerLink]="['/channels', channel.channel_id]"> <a class="cell-link" [routerLink]="['/channels', channel.channel_id]">
<nz-tag [nzColor]="getSubscriptionStatus(channel).color"> <nz-tag [nzColor]="getSubscriptionStatus(channel).color">
{{ getSubscriptionStatus(channel).label }} {{ getSubscriptionStatus(channel).label }}
</nz-tag> </nz-tag>
</a> </a>
} @else {
<nz-tag [nzColor]="getSubscriptionStatus(channel).color">
{{ getSubscriptionStatus(channel).label }}
</nz-tag>
}
</td> </td>
<td> <td>
@if (isOwned(channel)) { @if (isOwned(channel)) {
@@ -105,16 +85,11 @@
} }
</td> </td>
<td> <td>
@if (isOwned(channel)) {
<a class="cell-link" [routerLink]="['/channels', channel.channel_id]"> <a class="cell-link" [routerLink]="['/channels', channel.channel_id]">
{{ channel.messages_sent }} {{ channel.messages_sent }}
</a> </a>
} @else {
{{ channel.messages_sent }}
}
</td> </td>
<td> <td>
@if (isOwned(channel)) {
<a class="cell-link" [routerLink]="['/channels', channel.channel_id]"> <a class="cell-link" [routerLink]="['/channels', channel.channel_id]">
@if (channel.timestamp_lastsent) { @if (channel.timestamp_lastsent) {
<div class="timestamp-absolute">{{ channel.timestamp_lastsent | date:'yyyy-MM-dd HH:mm:ss' }}</div> <div class="timestamp-absolute">{{ channel.timestamp_lastsent | date:'yyyy-MM-dd HH:mm:ss' }}</div>
@@ -123,14 +98,6 @@
<span class="text-muted">Never</span> <span class="text-muted">Never</span>
} }
</a> </a>
} @else {
@if (channel.timestamp_lastsent) {
<div class="timestamp-absolute">{{ channel.timestamp_lastsent | date:'yyyy-MM-dd HH:mm:ss' }}</div>
<div class="timestamp-relative">{{ channel.timestamp_lastsent | relativeTime }}</div>
} @else {
<span class="text-muted">Never</span>
}
}
</td> </td>
@if (expertMode()) { @if (expertMode()) {
<td> <td>