This repository has been archived on 2024-06-08. You can view files and clone it, but cannot push or open issues or pull requests.
SolarAgent/lib/widgets/posts/reactions.dart
2024-03-24 13:34:29 +08:00

170 lines
5.3 KiB
Dart

import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:solaragent/auth.dart';
import 'package:solaragent/models/feed.dart';
class ReactionList extends StatefulWidget {
static const Map<String, Map<String, dynamic>> emojis = {
'thumb_up': {'icon': '👍', 'attitude': 1},
'clap': {'icon': '👏', 'attitude': 1}
};
final Feed parent;
final void Function(String symbol, int num) onReact;
const ReactionList({super.key, required this.parent, required this.onReact});
@override
State<ReactionList> createState() => _ReactionListState();
}
class _ReactionListState extends State<ReactionList> {
bool isSubmitting = false;
void viewReactMenu(BuildContext context) {
showModalBottomSheet(
context: context,
builder: (context) {
return ListView.builder(
padding: const EdgeInsets.all(8),
itemCount: ReactionList.emojis.length,
itemBuilder: (BuildContext context, int index) {
var element = ReactionList.emojis.entries.toList()[index];
return InkWell(
borderRadius: const BorderRadius.all(
Radius.circular(64),
),
onTap: () async {
await doReact(element.key, element.value['attitude']);
},
child: ListTile(
title: Text(element.value['icon']),
subtitle: Text(
":${element.key}:",
style: const TextStyle(fontFamily: "monospace"),
),
),
);
});
},
);
}
Future<void> doReact(String symbol, int attitude) async {
if (!await authClient.isAuthorized()) return;
var dataset = "${widget.parent.modelType}s";
var alias = widget.parent.id;
var uri = Uri.parse(
"https://co.solsynth.dev/api/p/$dataset/$alias/react",
);
setState(() => isSubmitting = true);
var res = await authClient.client!.post(
uri,
headers: <String, String>{
'Content-Type': 'application/json',
},
body: jsonEncode(<String, dynamic>{
'symbol': symbol,
'attitude': attitude,
}),
);
if (res.statusCode == 201) {
widget.onReact(symbol, 1);
} else if (res.statusCode == 204) {
widget.onReact(symbol, -1);
} else {
var message = utf8.decode(res.bodyBytes);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("Something went wrong... $message")),
);
}
setState(() => isSubmitting = false);
}
List<MapEntry<String, dynamic>> getReactionEntries() =>
widget.parent.reactionList?.entries.toList() ?? List.empty();
@override
Widget build(BuildContext context) {
return Column(
children: [
// Title
Container(
padding: const EdgeInsets.only(left: 10, right: 10, top: 20),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Padding(
padding: const EdgeInsets.symmetric(
horizontal: 8.0,
vertical: 12.0,
),
child: Text(
'Reactions',
style: Theme
.of(context)
.textTheme
.headlineSmall,
),
),
FutureBuilder(
future: authClient.isAuthorized(),
builder: (context, snapshot) {
if (snapshot.hasData && snapshot.data == true) {
return TextButton.icon(
icon: const Icon(Icons.add_reaction),
label: const Text("REACT"),
onPressed:
isSubmitting ? null : () => viewReactMenu(context),
);
} else {
return Container();
}
},
),
],
),
),
// Loading indicator
isSubmitting ? const LinearProgressIndicator() : Container(),
// Data list
Expanded(
child: ListView.separated(
itemCount: getReactionEntries().length,
itemBuilder: (BuildContext context, int index) {
var element = getReactionEntries()[index];
return InkWell(
onTap: isSubmitting
? null
: () {
doReact(
element.key,
ReactionList.emojis[element.key]!['attitude'],
);
},
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 6.0),
child: ListTile(
title: Text(
"${ReactionList.emojis[element.key]!['icon']} x${element
.value.toString()}",
),
subtitle: Text(
":${element.key}:",
style: const TextStyle(fontFamily: "monospace"),
),
),
));
},
separatorBuilder: (context, index) => const Divider(),
),
),
],
);
}
}