channel_message_list
This commit is contained in:
parent
778451fa4c
commit
be7035978b
@ -1,81 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
// https://stackoverflow.com/questions/46480221/flutter-floating-action-button-with-speed-dail
|
||||
|
||||
class FabWithIcons extends StatefulWidget {
|
||||
FabWithIcons({super.key, required this.icons, required this.onIconTapped});
|
||||
final List<IconData> icons;
|
||||
final ValueChanged<int> onIconTapped;
|
||||
|
||||
@override
|
||||
State createState() => FabWithIconsState();
|
||||
}
|
||||
|
||||
class FabWithIconsState extends State<FabWithIcons> with TickerProviderStateMixin {
|
||||
late AnimationController _controller;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_controller = AnimationController(
|
||||
vsync: this,
|
||||
duration: const Duration(milliseconds: 250),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: List.generate(widget.icons.length, (int index) {
|
||||
return _buildChild(index);
|
||||
}).toList()
|
||||
..add(
|
||||
_buildFab(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildChild(int index) {
|
||||
Color backgroundColor = Theme.of(context).cardColor;
|
||||
Color foregroundColor = Theme.of(context).secondaryHeaderColor;
|
||||
return Container(
|
||||
height: 70.0,
|
||||
width: 56.0,
|
||||
alignment: FractionalOffset.topCenter,
|
||||
child: ScaleTransition(
|
||||
scale: CurvedAnimation(
|
||||
parent: _controller,
|
||||
curve: Interval(0.0, 1.0 - index / widget.icons.length / 2.0, curve: Curves.easeOut),
|
||||
),
|
||||
child: FloatingActionButton(
|
||||
backgroundColor: backgroundColor,
|
||||
mini: true,
|
||||
child: Icon(widget.icons[index], color: foregroundColor),
|
||||
onPressed: () => _onTapped(index),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildFab() {
|
||||
return FloatingActionButton(
|
||||
onPressed: () {
|
||||
if (_controller.isDismissed) {
|
||||
_controller.forward();
|
||||
} else {
|
||||
_controller.reverse();
|
||||
}
|
||||
},
|
||||
tooltip: 'Increment',
|
||||
elevation: 2.0,
|
||||
child: const Icon(Icons.add),
|
||||
);
|
||||
}
|
||||
|
||||
void _onTapped(int index) {
|
||||
_controller.reverse();
|
||||
widget.onIconTapped(index);
|
||||
}
|
||||
}
|
@ -3,17 +3,20 @@ import 'package:flutter/material.dart';
|
||||
class HidableFAB extends StatelessWidget {
|
||||
final VoidCallback? onPressed;
|
||||
final IconData icon;
|
||||
final Object heroTag;
|
||||
|
||||
const HidableFAB({
|
||||
super.key,
|
||||
this.onPressed,
|
||||
required this.icon,
|
||||
required this.heroTag,
|
||||
});
|
||||
|
||||
Widget build(BuildContext context) {
|
||||
return Visibility(
|
||||
visible: MediaQuery.viewInsetsOf(context).bottom == 0.0, // hide when keyboard is shown
|
||||
child: FloatingActionButton(
|
||||
heroTag: this.heroTag,
|
||||
onPressed: onPressed,
|
||||
shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(17))),
|
||||
elevation: 2.0,
|
||||
|
@ -70,6 +70,16 @@ class Channel extends HiveObject implements FieldDebuggable {
|
||||
('messagesSent', '${this.messagesSent}'),
|
||||
];
|
||||
}
|
||||
|
||||
ChannelPreview toPreview() {
|
||||
return ChannelPreview(
|
||||
channelID: this.channelID,
|
||||
ownerUserID: this.ownerUserID,
|
||||
internalName: this.internalName,
|
||||
displayName: this.displayName,
|
||||
descriptionName: this.descriptionName,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ChannelWithSubscription {
|
||||
|
@ -76,6 +76,7 @@ class _SCNNavLayoutState extends State<SCNNavLayout> {
|
||||
bottomNavigationBar: _buildNavBar(context),
|
||||
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
|
||||
floatingActionButton: HidableFAB(
|
||||
heroTag: 'fab_main',
|
||||
onPressed: _onFABTapped,
|
||||
icon: FontAwesomeIcons.solidPaperPlaneTop,
|
||||
),
|
||||
|
@ -155,17 +155,17 @@ class _ChannelRootPageState extends State<ChannelRootPage> with RouteAware {
|
||||
channel: item.channel,
|
||||
subscription: item.subscription,
|
||||
onPressed: () {
|
||||
Navi.push(context, () => ChannelViewPage(channel: item.channel, subscription: item.subscription, needsReload: _enqueueReload));
|
||||
Navi.push(context, () => ChannelViewPage(channelID: item.channel.channelID, preloadedData: (item.channel, item.subscription), needsReload: _enqueueReload));
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
floatingActionButton: FloatingActionButton(
|
||||
heroTag: 'fab_channel_list_qr',
|
||||
onPressed: () {
|
||||
//TODO scan qr code to subscribe channel
|
||||
},
|
||||
backgroundColor: ,
|
||||
child: const Icon(FontAwesomeIcons.qrcode),
|
||||
),
|
||||
);
|
||||
|
@ -1,4 +1,6 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
@ -6,8 +8,11 @@ import 'package:simplecloudnotifier/api/api_client.dart';
|
||||
import 'package:simplecloudnotifier/models/channel.dart';
|
||||
import 'package:simplecloudnotifier/models/scn_message.dart';
|
||||
import 'package:simplecloudnotifier/models/subscription.dart';
|
||||
import 'package:simplecloudnotifier/pages/channel_message_view/channel_message_view.dart';
|
||||
import 'package:simplecloudnotifier/state/app_auth.dart';
|
||||
import 'package:simplecloudnotifier/state/scn_data_cache.dart';
|
||||
import 'package:simplecloudnotifier/utils/navi.dart';
|
||||
import 'package:simplecloudnotifier/utils/toaster.dart';
|
||||
|
||||
class ChannelListItem extends StatefulWidget {
|
||||
static final _dateFormat = DateFormat('yyyy-MM-dd kk:mm');
|
||||
@ -56,7 +61,6 @@ class _ChannelListItemState extends State<ChannelListItem> {
|
||||
shape: BeveledRectangleBorder(borderRadius: BorderRadius.circular(0)),
|
||||
color: Theme.of(context).cardTheme.color,
|
||||
child: InkWell(
|
||||
splashColor: Theme.of(context).splashColor,
|
||||
onTap: widget.onPressed,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8),
|
||||
@ -98,6 +102,16 @@ class _ChannelListItemState extends State<ChannelListItem> {
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(width: 4),
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
Navi.push(context, () => ChannelMessageViewPage(channel: this.widget.channel));
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8),
|
||||
child: Icon(FontAwesomeIcons.solidEnvelopes, color: Theme.of(context).colorScheme.onPrimaryContainer.withAlpha(128), size: 24),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
105
flutter/lib/pages/channel_message_view/channel_message_view.dart
Normal file
105
flutter/lib/pages/channel_message_view/channel_message_view.dart
Normal file
@ -0,0 +1,105 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart';
|
||||
import 'package:simplecloudnotifier/api/api_client.dart';
|
||||
import 'package:simplecloudnotifier/components/layout/scaffold.dart';
|
||||
import 'package:simplecloudnotifier/models/channel.dart';
|
||||
import 'package:simplecloudnotifier/models/scn_message.dart';
|
||||
import 'package:simplecloudnotifier/pages/message_list/message_list_item.dart';
|
||||
import 'package:simplecloudnotifier/pages/message_view/message_view.dart';
|
||||
import 'package:simplecloudnotifier/settings/app_settings.dart';
|
||||
import 'package:simplecloudnotifier/state/app_auth.dart';
|
||||
import 'package:simplecloudnotifier/state/application_log.dart';
|
||||
import 'package:simplecloudnotifier/state/scn_data_cache.dart';
|
||||
import 'package:simplecloudnotifier/utils/navi.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class ChannelMessageViewPage extends StatefulWidget {
|
||||
const ChannelMessageViewPage({
|
||||
required this.channel,
|
||||
super.key,
|
||||
});
|
||||
|
||||
final Channel channel;
|
||||
|
||||
@override
|
||||
State<ChannelMessageViewPage> createState() => _ChannelMessageViewPageState();
|
||||
}
|
||||
|
||||
class _ChannelMessageViewPageState extends State<ChannelMessageViewPage> {
|
||||
PagingController<String, SCNMessage> _pagingController = PagingController.fromValue(PagingState(nextPageKey: null, itemList: [], error: null), firstPageKey: '@start');
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
_pagingController.addPageRequestListener(_fetchPage);
|
||||
|
||||
_pagingController.refresh();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_pagingController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
Future<void> _fetchPage(String thisPageToken) async {
|
||||
final acc = Provider.of<AppAuth>(context, listen: false);
|
||||
final cfg = Provider.of<AppSettings>(context, listen: false);
|
||||
|
||||
ApplicationLog.debug('Start ChannelMessageViewPage::_pagingController::_fetchPage [ ${thisPageToken} ]');
|
||||
|
||||
if (!acc.isAuth()) {
|
||||
_pagingController.error = 'Not logged in';
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
final (npt, newItems) = await APIClient.getMessageList(acc, thisPageToken, pageSize: cfg.messagePageSize, channelIDs: [this.widget.channel.channelID]);
|
||||
|
||||
SCNDataCache().addToMessageCache(newItems); // no await
|
||||
|
||||
if (npt == '@end') {
|
||||
_pagingController.appendLastPage(newItems);
|
||||
} else {
|
||||
_pagingController.appendPage(newItems, npt);
|
||||
}
|
||||
} catch (exc, trace) {
|
||||
_pagingController.error = exc.toString();
|
||||
ApplicationLog.error('Failed to list channel-messages: ' + exc.toString(), trace: trace);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SCNScaffold(
|
||||
title: this.widget.channel.displayName,
|
||||
showSearch: false,
|
||||
showShare: false,
|
||||
child: _buildMessageList(context),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildMessageList(BuildContext context) {
|
||||
return Padding(
|
||||
padding: EdgeInsets.fromLTRB(8, 4, 8, 4),
|
||||
child: RefreshIndicator(
|
||||
onRefresh: () => Future.sync(
|
||||
() => _pagingController.refresh(),
|
||||
),
|
||||
child: PagedListView<String, SCNMessage>(
|
||||
pagingController: _pagingController,
|
||||
builderDelegate: PagedChildBuilderDelegate<SCNMessage>(
|
||||
itemBuilder: (context, item, index) => MessageListItem(
|
||||
message: item,
|
||||
allChannels: {this.widget.channel.channelID: this.widget.channel},
|
||||
onPressed: () {
|
||||
Navi.push(context, () => MessageViewPage(message: item));
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -1,5 +1,4 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||
import 'package:qr_flutter/qr_flutter.dart';
|
||||
import 'package:share_plus/share_plus.dart';
|
||||
@ -8,24 +7,26 @@ import 'package:simplecloudnotifier/components/layout/scaffold.dart';
|
||||
import 'package:simplecloudnotifier/models/channel.dart';
|
||||
import 'package:simplecloudnotifier/models/subscription.dart';
|
||||
import 'package:simplecloudnotifier/models/user.dart';
|
||||
import 'package:simplecloudnotifier/pages/channel_message_view/channel_message_view.dart';
|
||||
import 'package:simplecloudnotifier/state/app_auth.dart';
|
||||
import 'package:simplecloudnotifier/state/app_bar_state.dart';
|
||||
import 'package:simplecloudnotifier/state/application_log.dart';
|
||||
import 'package:simplecloudnotifier/types/immediate_future.dart';
|
||||
import 'package:simplecloudnotifier/utils/navi.dart';
|
||||
import 'package:simplecloudnotifier/utils/toaster.dart';
|
||||
import 'package:simplecloudnotifier/utils/ui.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class ChannelViewPage extends StatefulWidget {
|
||||
const ChannelViewPage({
|
||||
required this.channel,
|
||||
required this.subscription,
|
||||
required this.channelID,
|
||||
required this.preloadedData,
|
||||
required this.needsReload,
|
||||
super.key,
|
||||
});
|
||||
|
||||
final Channel channel;
|
||||
final Subscription? subscription;
|
||||
final String channelID;
|
||||
final (Channel, Subscription?)? preloadedData;
|
||||
|
||||
final void Function()? needsReload;
|
||||
|
||||
@ -35,6 +36,8 @@ class ChannelViewPage extends StatefulWidget {
|
||||
|
||||
enum EditState { none, editing, saving }
|
||||
|
||||
enum ChannelViewPageInitState { loading, okay, error }
|
||||
|
||||
class _ChannelViewPageState extends State<ChannelViewPage> {
|
||||
late ImmediateFuture<String?> _futureSubscribeKey;
|
||||
late ImmediateFuture<List<(Subscription, UserPreview?)>> _futureSubscriptions;
|
||||
@ -51,15 +54,58 @@ class _ChannelViewPageState extends State<ChannelViewPage> {
|
||||
EditState _editDescriptionName = EditState.none;
|
||||
String? _descriptionNameOverride = null;
|
||||
|
||||
ChannelPreview? channelPreview;
|
||||
Channel? channel;
|
||||
Subscription? subscription;
|
||||
|
||||
ChannelViewPageInitState loadingState = ChannelViewPageInitState.loading;
|
||||
String errorMessage = '';
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_initStateAsync();
|
||||
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
void _initStateAsync() async {
|
||||
final userAcc = Provider.of<AppAuth>(context, listen: false);
|
||||
|
||||
if (widget.channel.ownerUserID == userAcc.userID) {
|
||||
if (widget.channel.subscribeKey != null) {
|
||||
_futureSubscribeKey = ImmediateFuture<String?>.ofValue(widget.channel.subscribeKey);
|
||||
if (widget.preloadedData != null) {
|
||||
channelPreview = widget.preloadedData!.$1.toPreview();
|
||||
channel = widget.preloadedData!.$1;
|
||||
subscription = widget.preloadedData!.$2;
|
||||
} else {
|
||||
_futureSubscribeKey = ImmediateFuture<String?>.ofFuture(_getSubScribeKey(userAcc));
|
||||
try {
|
||||
var p = await APIClient.getChannelPreview(userAcc, widget.channelID);
|
||||
channelPreview = p;
|
||||
if (p.ownerUserID == userAcc.userID) {
|
||||
var r = await APIClient.getChannel(userAcc, widget.channelID);
|
||||
channel = r.channel;
|
||||
subscription = r.subscription;
|
||||
} else {
|
||||
channel = null;
|
||||
subscription = null; //TODO get own subscription on this channel, even though its foreign channel
|
||||
}
|
||||
} catch (exc, trace) {
|
||||
ApplicationLog.error('Failed to load data: ' + exc.toString(), trace: trace);
|
||||
Toaster.error("Error", 'Failed to load data');
|
||||
this.errorMessage = 'Failed to load data: ' + exc.toString();
|
||||
this.loadingState = ChannelViewPageInitState.error;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this.loadingState = ChannelViewPageInitState.okay;
|
||||
|
||||
assert(channelPreview != null);
|
||||
|
||||
if (this.channelPreview!.ownerUserID == userAcc.userID) {
|
||||
if (this.channel != null && this.channel!.subscribeKey != null) {
|
||||
_futureSubscribeKey = ImmediateFuture<String?>.ofValue(this.channel!.subscribeKey);
|
||||
} else {
|
||||
_futureSubscribeKey = ImmediateFuture<String?>.ofFuture(_getSubscribeKey(userAcc));
|
||||
}
|
||||
_futureSubscriptions = ImmediateFuture<List<(Subscription, UserPreview?)>>.ofFuture(_listSubscriptions(userAcc));
|
||||
} else {
|
||||
@ -67,7 +113,7 @@ class _ChannelViewPageState extends State<ChannelViewPage> {
|
||||
_futureSubscriptions = ImmediateFuture<List<(Subscription, UserPreview?)>>.ofValue([]);
|
||||
}
|
||||
|
||||
if (widget.channel.ownerUserID == userAcc.userID) {
|
||||
if (this.channelPreview!.ownerUserID == userAcc.userID) {
|
||||
var cacheUser = userAcc.getUserOrNull();
|
||||
if (cacheUser != null) {
|
||||
_futureOwner = ImmediateFuture<UserPreview>.ofValue(cacheUser.toPreview());
|
||||
@ -75,10 +121,8 @@ class _ChannelViewPageState extends State<ChannelViewPage> {
|
||||
_futureOwner = ImmediateFuture<UserPreview>.ofFuture(_getOwner(userAcc));
|
||||
}
|
||||
} else {
|
||||
_futureOwner = ImmediateFuture<UserPreview>.ofFuture(APIClient.getUserPreview(userAcc, widget.channel.ownerUserID));
|
||||
_futureOwner = ImmediateFuture<UserPreview>.ofFuture(APIClient.getUserPreview(userAcc, this.channelPreview!.ownerUserID));
|
||||
}
|
||||
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
@ -90,19 +134,30 @@ class _ChannelViewPageState extends State<ChannelViewPage> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final userAcc = Provider.of<AppAuth>(context, listen: false);
|
||||
|
||||
Widget child;
|
||||
|
||||
if (loadingState == ChannelViewPageInitState.loading) {
|
||||
child = Center(child: CircularProgressIndicator());
|
||||
} else if (loadingState == ChannelViewPageInitState.error) {
|
||||
child = Center(child: Text('Error: ' + errorMessage)); //TODO better error
|
||||
} else if (loadingState == ChannelViewPageInitState.okay && channelPreview!.ownerUserID == userAcc.userID) {
|
||||
child = _buildOwnedChannelView(context, this.channel!);
|
||||
} else {
|
||||
child = _buildForeignChannelView(context, this.channelPreview!);
|
||||
}
|
||||
|
||||
return SCNScaffold(
|
||||
title: 'Channel',
|
||||
showSearch: false,
|
||||
showShare: false,
|
||||
child: _buildChannelView(context),
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildChannelView(BuildContext context) {
|
||||
final userAccUserID = context.select<AppAuth, String?>((v) => v.userID);
|
||||
|
||||
final isOwned = (widget.channel.ownerUserID == userAccUserID);
|
||||
final isSubscribed = (widget.subscription != null && widget.subscription!.confirmed);
|
||||
Widget _buildOwnedChannelView(BuildContext context, Channel channel) {
|
||||
final isSubscribed = (subscription != null && subscription!.confirmed);
|
||||
|
||||
return SingleChildScrollView(
|
||||
child: Padding(
|
||||
@ -116,31 +171,33 @@ class _ChannelViewPageState extends State<ChannelViewPage> {
|
||||
context: context,
|
||||
icon: FontAwesomeIcons.solidIdCardClip,
|
||||
title: 'ChannelID',
|
||||
values: [widget.channel.channelID],
|
||||
values: [channel.channelID],
|
||||
),
|
||||
UI.metaCard(
|
||||
context: context,
|
||||
icon: FontAwesomeIcons.solidInputNumeric,
|
||||
title: 'InternalName',
|
||||
values: [widget.channel.internalName],
|
||||
values: [channel.internalName],
|
||||
),
|
||||
_buildDisplayNameCard(context, isOwned),
|
||||
_buildDescriptionNameCard(context, isOwned),
|
||||
_buildDisplayNameCard(context, true),
|
||||
_buildDescriptionNameCard(context, true),
|
||||
UI.metaCard(
|
||||
context: context,
|
||||
icon: FontAwesomeIcons.solidDiagramSubtask,
|
||||
title: 'Subscription (own)',
|
||||
values: [_formatSubscriptionStatus(widget.subscription)],
|
||||
values: [_formatSubscriptionStatus(this.subscription)],
|
||||
iconActions: isSubscribed ? [(FontAwesomeIcons.solidSquareXmark, _unsubscribe)] : [(FontAwesomeIcons.solidSquareRss, _subscribe)],
|
||||
),
|
||||
_buildForeignSubscriptions(context),
|
||||
_buildOwnerCard(context, isOwned),
|
||||
_buildOwnerCard(context, true),
|
||||
UI.metaCard(
|
||||
context: context,
|
||||
icon: FontAwesomeIcons.solidEnvelope,
|
||||
title: 'Messages',
|
||||
values: [widget.channel.messagesSent.toString()],
|
||||
mainAction: () {/*TODO*/},
|
||||
values: [channel.messagesSent.toString()],
|
||||
mainAction: () {
|
||||
Navi.push(context, () => ChannelMessageViewPage(channel: channel));
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
@ -148,6 +205,45 @@ class _ChannelViewPageState extends State<ChannelViewPage> {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildForeignChannelView(BuildContext context, ChannelPreview channel) {
|
||||
final isSubscribed = (subscription != null && subscription!.confirmed);
|
||||
|
||||
return SingleChildScrollView(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.fromLTRB(24, 16, 24, 16),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
SizedBox(height: 8),
|
||||
UI.metaCard(
|
||||
context: context,
|
||||
icon: FontAwesomeIcons.solidIdCardClip,
|
||||
title: 'ChannelID',
|
||||
values: [channel.channelID],
|
||||
),
|
||||
UI.metaCard(
|
||||
context: context,
|
||||
icon: FontAwesomeIcons.solidInputNumeric,
|
||||
title: 'InternalName',
|
||||
values: [channel.internalName],
|
||||
),
|
||||
_buildDisplayNameCard(context, false),
|
||||
_buildDescriptionNameCard(context, false),
|
||||
UI.metaCard(
|
||||
context: context,
|
||||
icon: FontAwesomeIcons.solidDiagramSubtask,
|
||||
title: 'Subscription (own)',
|
||||
values: [_formatSubscriptionStatus(subscription)],
|
||||
iconActions: isSubscribed ? [(FontAwesomeIcons.solidSquareXmark, _unsubscribe)] : [(FontAwesomeIcons.solidSquareRss, _subscribe)],
|
||||
),
|
||||
_buildForeignSubscriptions(context),
|
||||
_buildOwnerCard(context, false),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildForeignSubscriptions(BuildContext context) {
|
||||
return FutureBuilder(
|
||||
future: _futureSubscriptions.future,
|
||||
@ -156,7 +252,7 @@ class _ChannelViewPageState extends State<ChannelViewPage> {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
for (final (sub, user) in snapshot.data!.where((v) => v.$1.subscriptionID != widget.subscription?.subscriptionID))
|
||||
for (final (sub, user) in snapshot.data!.where((v) => v.$1.subscriptionID != subscription?.subscriptionID))
|
||||
UI.metaCard(
|
||||
context: context,
|
||||
icon: FontAwesomeIcons.solidDiagramSuccessor,
|
||||
@ -182,14 +278,14 @@ class _ChannelViewPageState extends State<ChannelViewPage> {
|
||||
context: context,
|
||||
icon: FontAwesomeIcons.solidUser,
|
||||
title: 'Owner',
|
||||
values: [widget.channel.ownerUserID + (isOwned ? ' (you)' : ''), if (snapshot.data?.username != null) snapshot.data!.username!],
|
||||
values: [channelPreview!.ownerUserID + (isOwned ? ' (you)' : ''), if (snapshot.data?.username != null) snapshot.data!.username!],
|
||||
);
|
||||
} else {
|
||||
return UI.metaCard(
|
||||
context: context,
|
||||
icon: FontAwesomeIcons.solidUser,
|
||||
title: 'Owner',
|
||||
values: [widget.channel.ownerUserID + (isOwned ? ' (you)' : '')],
|
||||
values: [channelPreview!.ownerUserID + (isOwned ? ' (you)' : '')],
|
||||
);
|
||||
}
|
||||
},
|
||||
@ -201,10 +297,10 @@ class _ChannelViewPageState extends State<ChannelViewPage> {
|
||||
future: _futureSubscribeKey.future,
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.hasData && snapshot.data != null) {
|
||||
var text = 'TODO' + '\n' + widget.channel.channelID + '\n' + snapshot.data!; //TODO deeplink-y (also perhaps just bas64 everything together?)
|
||||
var text = 'TODO' + '\n' + channel!.channelID + '\n' + snapshot.data!; //TODO deeplink-y (also perhaps just bas64 everything together?)
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
Share.share(text, subject: _displayNameOverride ?? widget.channel.displayName);
|
||||
Share.share(text, subject: _displayNameOverride ?? channel!.displayName);
|
||||
},
|
||||
child: Center(
|
||||
child: QrImageView(
|
||||
@ -269,7 +365,7 @@ class _ChannelViewPageState extends State<ChannelViewPage> {
|
||||
context: context,
|
||||
icon: FontAwesomeIcons.solidInputText,
|
||||
title: 'DisplayName',
|
||||
values: [_displayNameOverride ?? widget.channel.displayName],
|
||||
values: [_displayNameOverride ?? channelPreview!.displayName],
|
||||
iconActions: isOwned ? [(FontAwesomeIcons.penToSquare, _showEditDisplayName)] : [],
|
||||
);
|
||||
} else if (_editDisplayName == EditState.saving) {
|
||||
@ -325,7 +421,7 @@ class _ChannelViewPageState extends State<ChannelViewPage> {
|
||||
context: context,
|
||||
icon: FontAwesomeIcons.solidInputPipe,
|
||||
title: 'Description',
|
||||
values: [_descriptionNameOverride ?? widget.channel.descriptionName ?? ''],
|
||||
values: [_descriptionNameOverride ?? channelPreview?.descriptionName ?? ''],
|
||||
iconActions: isOwned ? [(FontAwesomeIcons.penToSquare, _showEditDescriptionName)] : [],
|
||||
);
|
||||
} else if (_editDescriptionName == EditState.saving) {
|
||||
@ -361,7 +457,7 @@ class _ChannelViewPageState extends State<ChannelViewPage> {
|
||||
|
||||
void _showEditDisplayName() {
|
||||
setState(() {
|
||||
_ctrlDisplayName.text = _displayNameOverride ?? widget.channel.displayName;
|
||||
_ctrlDisplayName.text = _displayNameOverride ?? channelPreview?.displayName ?? '';
|
||||
_editDisplayName = EditState.editing;
|
||||
if (_editDescriptionName == EditState.editing) _editDescriptionName = EditState.none;
|
||||
});
|
||||
@ -377,7 +473,7 @@ class _ChannelViewPageState extends State<ChannelViewPage> {
|
||||
_editDisplayName = EditState.saving;
|
||||
});
|
||||
|
||||
final newChannel = await APIClient.updateChannel(userAcc, widget.channel.channelID, displayName: newName);
|
||||
final newChannel = await APIClient.updateChannel(userAcc, widget.channelID, displayName: newName);
|
||||
|
||||
setState(() {
|
||||
_editDisplayName = EditState.none;
|
||||
@ -393,7 +489,7 @@ class _ChannelViewPageState extends State<ChannelViewPage> {
|
||||
|
||||
void _showEditDescriptionName() {
|
||||
setState(() {
|
||||
_ctrlDescriptionName.text = _descriptionNameOverride ?? widget.channel.descriptionName ?? '';
|
||||
_ctrlDescriptionName.text = _descriptionNameOverride ?? channelPreview?.descriptionName ?? '';
|
||||
_editDescriptionName = EditState.editing;
|
||||
if (_editDisplayName == EditState.editing) _editDisplayName = EditState.none;
|
||||
});
|
||||
@ -409,7 +505,7 @@ class _ChannelViewPageState extends State<ChannelViewPage> {
|
||||
_editDescriptionName = EditState.saving;
|
||||
});
|
||||
|
||||
final newChannel = await APIClient.updateChannel(userAcc, widget.channel.channelID, descriptionName: newName);
|
||||
final newChannel = await APIClient.updateChannel(userAcc, widget.channelID, descriptionName: newName);
|
||||
|
||||
setState(() {
|
||||
_editDescriptionName = EditState.none;
|
||||
@ -445,13 +541,13 @@ class _ChannelViewPageState extends State<ChannelViewPage> {
|
||||
}
|
||||
}
|
||||
|
||||
Future<String?> _getSubScribeKey(AppAuth auth) async {
|
||||
Future<String?> _getSubscribeKey(AppAuth auth) async {
|
||||
try {
|
||||
await Future.delayed(const Duration(seconds: 0), () {}); // this is annoyingly important - otherwise we call setLoadingIndeterminate directly in initStat() and get an exception....
|
||||
|
||||
_incLoadingIndeterminateCounter(1);
|
||||
|
||||
var channel = await APIClient.getChannel(auth, widget.channel.channelID);
|
||||
var channel = await APIClient.getChannel(auth, widget.channelID);
|
||||
|
||||
//await Future.delayed(const Duration(seconds: 10), () {});
|
||||
|
||||
@ -467,7 +563,7 @@ class _ChannelViewPageState extends State<ChannelViewPage> {
|
||||
|
||||
_incLoadingIndeterminateCounter(1);
|
||||
|
||||
var subs = await APIClient.getChannelSubscriptions(auth, widget.channel.channelID);
|
||||
var subs = await APIClient.getChannelSubscriptions(auth, widget.channelID);
|
||||
|
||||
var userMap = {for (var v in (await Future.wait(subs.map((e) => e.subscriberUserID).toSet().map((e) => APIClient.getUserPreview(auth, e)).toList()))) v.userID: v};
|
||||
|
||||
@ -485,7 +581,7 @@ class _ChannelViewPageState extends State<ChannelViewPage> {
|
||||
|
||||
_incLoadingIndeterminateCounter(1);
|
||||
|
||||
final owner = APIClient.getUserPreview(auth, widget.channel.ownerUserID);
|
||||
final owner = APIClient.getUserPreview(auth, channelPreview!.ownerUserID);
|
||||
|
||||
//await Future.delayed(const Duration(seconds: 10), () {});
|
||||
|
||||
|
@ -10,8 +10,10 @@ import 'package:simplecloudnotifier/models/channel.dart';
|
||||
import 'package:simplecloudnotifier/models/keytoken.dart';
|
||||
import 'package:simplecloudnotifier/models/scn_message.dart';
|
||||
import 'package:simplecloudnotifier/models/user.dart';
|
||||
import 'package:simplecloudnotifier/pages/channel_view/channel_view.dart';
|
||||
import 'package:simplecloudnotifier/state/app_auth.dart';
|
||||
import 'package:simplecloudnotifier/state/app_bar_state.dart';
|
||||
import 'package:simplecloudnotifier/utils/navi.dart';
|
||||
import 'package:simplecloudnotifier/utils/toaster.dart';
|
||||
import 'package:simplecloudnotifier/utils/ui.dart';
|
||||
|
||||
@ -157,7 +159,11 @@ class _MessageViewPageState extends State<MessageViewPage> {
|
||||
icon: FontAwesomeIcons.solidSnake,
|
||||
title: 'Channel',
|
||||
values: [message.channelID, channel?.displayName ?? message.channelInternalName],
|
||||
mainAction: () => {/*TODO*/},
|
||||
mainAction: (channel != null)
|
||||
? () {
|
||||
Navi.push(context, () => ChannelViewPage(channelID: channel.channelID, preloadedData: null, needsReload: null));
|
||||
}
|
||||
: null,
|
||||
),
|
||||
UI.metaCard(
|
||||
context: context,
|
||||
|
Loading…
Reference in New Issue
Block a user