203 lines
8.6 KiB
Dart
203 lines
8.6 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
|
import 'package:provider/provider.dart';
|
|
import 'package:simplecloudnotifier/api/api_client.dart';
|
|
import 'package:simplecloudnotifier/models/channel.dart';
|
|
import 'package:simplecloudnotifier/models/scan_result.dart';
|
|
import 'package:simplecloudnotifier/models/subscription.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/application_log.dart';
|
|
import 'package:simplecloudnotifier/utils/navi.dart';
|
|
import 'package:simplecloudnotifier/utils/toaster.dart';
|
|
import 'package:simplecloudnotifier/utils/ui.dart';
|
|
|
|
class ChannelScannerResultChannelSubscribe extends StatefulWidget {
|
|
final ScanResultChannelSubscribe value;
|
|
|
|
const ChannelScannerResultChannelSubscribe({required this.value}) : super();
|
|
|
|
@override
|
|
State<ChannelScannerResultChannelSubscribe> createState() => _ChannelScannerResultChannelSubscribeState();
|
|
}
|
|
|
|
class _ChannelScannerResultChannelSubscribeState extends State<ChannelScannerResultChannelSubscribe> {
|
|
Future<(ChannelPreview, UserPreview)?> _fetchDataFuture;
|
|
|
|
_ChannelScannerResultChannelSubscribeState() : _fetchDataFuture = Future.value(null); // Initial dummy future
|
|
|
|
Subscription? overrideSubscription = null;
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
|
|
final auth = Provider.of<AppAuth>(context, listen: false);
|
|
setState(() {
|
|
_fetchDataFuture = _fetchData(auth);
|
|
});
|
|
}
|
|
|
|
Future<(ChannelPreview, UserPreview)?> _fetchData(AppAuth auth) async {
|
|
ChannelPreview? channel = null;
|
|
try {
|
|
channel = await APIClient.getChannelPreview(auth, widget.value.channelID);
|
|
} catch (e, stackTrace) {
|
|
Toaster.error("Error", 'Failed to fetch channel preview: ${e.toString()}');
|
|
ApplicationLog.error('Failed to fetch channel (preview) for ${widget.value.channelID}', trace: stackTrace);
|
|
return null;
|
|
}
|
|
|
|
UserPreview? user = null;
|
|
try {
|
|
user = await APIClient.getUserPreview(auth, widget.value.ownerUserID);
|
|
} catch (e, stackTrace) {
|
|
Toaster.error("Error", 'Failed to fetch user preview: ${e.toString()}');
|
|
ApplicationLog.error('Failed to fetch user (preview) for ${widget.value.ownerUserID}', trace: stackTrace);
|
|
return null;
|
|
}
|
|
|
|
return (channel, user);
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return FutureBuilder<(ChannelPreview, UserPreview)?>(
|
|
future: _fetchDataFuture,
|
|
builder: (context, snapshot) {
|
|
final auth = Provider.of<AppAuth>(context, listen: false);
|
|
|
|
if (snapshot.connectionState == ConnectionState.waiting) {
|
|
return const Center(child: CircularProgressIndicator());
|
|
}
|
|
|
|
if (snapshot.hasError) {
|
|
return Text('Error: ${snapshot.error}'); //TODO better error display
|
|
}
|
|
|
|
if (snapshot.data == null) {
|
|
return Column(
|
|
spacing: 32,
|
|
children: [
|
|
Icon(FontAwesomeIcons.solidTriangleExclamation, size: 64, color: Colors.red[900]),
|
|
Text("Failed to parse QR", textAlign: TextAlign.center),
|
|
],
|
|
);
|
|
}
|
|
|
|
final (channel, user) = snapshot.data!;
|
|
|
|
final sub = overrideSubscription ?? channel.subscription;
|
|
|
|
return Column(
|
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
children: [
|
|
Text("SCN Channel", style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 20), textAlign: TextAlign.center),
|
|
const SizedBox(height: 16),
|
|
Row(
|
|
children: [
|
|
ConstrainedBox(child: Text("Name: ", style: const TextStyle(fontWeight: FontWeight.bold)), constraints: const BoxConstraints(minWidth: 100)),
|
|
Expanded(child: SingleChildScrollView(child: Text(channel.displayName), scrollDirection: Axis.horizontal)),
|
|
],
|
|
),
|
|
Row(
|
|
children: [
|
|
ConstrainedBox(child: Text("InternalName: ", style: const TextStyle(fontWeight: FontWeight.bold)), constraints: const BoxConstraints(minWidth: 100)),
|
|
Expanded(child: SingleChildScrollView(child: Text(channel.internalName, style: const TextStyle(fontStyle: FontStyle.italic)), scrollDirection: Axis.horizontal)),
|
|
],
|
|
),
|
|
Row(
|
|
children: [
|
|
ConstrainedBox(child: Text("ChannelID: ", style: const TextStyle(fontWeight: FontWeight.bold)), constraints: const BoxConstraints(minWidth: 100)),
|
|
Expanded(child: SingleChildScrollView(child: Text(channel.channelID, style: const TextStyle(fontStyle: FontStyle.italic)), scrollDirection: Axis.horizontal)),
|
|
],
|
|
),
|
|
Row(
|
|
children: [
|
|
ConstrainedBox(child: Text("Messages: ", style: const TextStyle(fontWeight: FontWeight.bold)), constraints: const BoxConstraints(minWidth: 100)),
|
|
Expanded(child: SingleChildScrollView(child: Text(channel.messagesSent.toString()), scrollDirection: Axis.horizontal)),
|
|
],
|
|
),
|
|
if (channel.descriptionName != null && channel.descriptionName!.isNotEmpty)
|
|
Row(
|
|
children: [
|
|
ConstrainedBox(child: Text("Description:", style: const TextStyle(fontWeight: FontWeight.bold)), constraints: const BoxConstraints(minWidth: 100)),
|
|
Expanded(child: SingleChildScrollView(child: Text(channel.descriptionName!), scrollDirection: Axis.horizontal)),
|
|
],
|
|
),
|
|
const SizedBox(height: 16),
|
|
Row(
|
|
children: [
|
|
ConstrainedBox(child: Text("Owner:", style: const TextStyle(fontWeight: FontWeight.bold)), constraints: const BoxConstraints(minWidth: 100)),
|
|
Expanded(child: SingleChildScrollView(child: Text((user.username ?? user.userID) + ((auth.userID != null && auth.userID! == user.userID) ? "\n(you)" : "")), scrollDirection: Axis.horizontal)),
|
|
],
|
|
),
|
|
Row(
|
|
children: [
|
|
ConstrainedBox(child: Text("UserID:", style: const TextStyle(fontWeight: FontWeight.bold)), constraints: const BoxConstraints(minWidth: 100)),
|
|
Expanded(child: SingleChildScrollView(child: Text(user.userID, style: const TextStyle(fontStyle: FontStyle.italic)), scrollDirection: Axis.horizontal)),
|
|
],
|
|
),
|
|
const SizedBox(height: 16),
|
|
Row(
|
|
children: [
|
|
ConstrainedBox(child: Text("Status:", style: const TextStyle(fontWeight: FontWeight.bold)), constraints: const BoxConstraints(minWidth: 100)),
|
|
Expanded(child: SingleChildScrollView(child: Text(_formatSubscriptionStatus(sub)), scrollDirection: Axis.horizontal)),
|
|
],
|
|
),
|
|
const SizedBox(height: 48),
|
|
if (sub == null)
|
|
UI.button(
|
|
text: 'Request Subscription',
|
|
onPressed: _onSubscribe,
|
|
color: Theme.of(context).colorScheme.primary,
|
|
textColor: Theme.of(context).colorScheme.onPrimary,
|
|
),
|
|
if (sub != null && sub.confirmed)
|
|
UI.button(
|
|
text: 'Go to channel',
|
|
onPressed: () {
|
|
Navi.pushOnRoot(context, () => ChannelViewPage(channelID: widget.value.channelID, preloadedData: null, needsReload: null));
|
|
},
|
|
color: Theme.of(context).colorScheme.primary,
|
|
textColor: Theme.of(context).colorScheme.onPrimary,
|
|
),
|
|
],
|
|
);
|
|
},
|
|
);
|
|
}
|
|
|
|
void _onSubscribe() async {
|
|
final auth = Provider.of<AppAuth>(context, listen: false);
|
|
try {
|
|
var sub = await APIClient.subscribeToChannelbyID(auth, widget.value.channelID, subscribeKey: widget.value.subscribeKey);
|
|
if (sub.confirmed) {
|
|
Toaster.success("Success", "Subscription request sent and auto-confirmed");
|
|
} else {
|
|
Toaster.success("Success", "Subscription request sent - pending confirmation");
|
|
}
|
|
setState(() {
|
|
overrideSubscription = sub;
|
|
});
|
|
} catch (e) {
|
|
Toaster.error("Error", 'Failed to send subscription-request: ${e.toString()}');
|
|
}
|
|
}
|
|
|
|
String _formatSubscriptionStatus(Subscription? sub) {
|
|
if (sub == null) {
|
|
return "Not Subscribed";
|
|
} else if (sub.confirmed) {
|
|
if (sub.active) {
|
|
return "Already Subscribed";
|
|
} else {
|
|
return "Already Subscribed (inactive)";
|
|
}
|
|
} else {
|
|
return "Unconfirmed Subscription";
|
|
}
|
|
}
|
|
}
|