Skip to content

Commit

Permalink
🚀 ⚡ Added Support for URL Previews, Fixed #10!
Browse files Browse the repository at this point in the history
  • Loading branch information
omegaui committed Mar 16, 2023
1 parent 27ce7cc commit b73e597
Show file tree
Hide file tree
Showing 3 changed files with 185 additions and 31 deletions.
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
import 'package:animated_text_kit/animated_text_kit.dart';
import 'package:chat_desk/core/io/message.dart';
import 'package:chat_desk/io/app_style.dart';
import 'package:chat_desk/ui/utils.dart';
import 'package:flutter/material.dart';
import 'package:metadata_fetch/metadata_fetch.dart';
import 'package:url_launcher/url_launcher_string.dart';

Map<String, dynamic> retrievedUrls = {};
Map<String, ImageProvider<Object>> retrievedUrlsImageCache = {};

class UrlChatComponent extends StatefulWidget {
const UrlChatComponent({super.key, required this.message});

Expand All @@ -16,46 +21,161 @@ class UrlChatComponent extends StatefulWidget {
class _UrlChatComponentState extends State<UrlChatComponent> {
bool hover = false;

Future<dynamic> _getMetaData() async {
if (retrievedUrls.containsKey(widget.message.message)) {
return retrievedUrls[widget.message.message];
}
dynamic map = await MetadataFetch.extract(widget.message.message);
retrievedUrls.putIfAbsent(widget.message.message, () => map);
return map;
}

@override
Widget build(BuildContext context) {
return Flexible(
child: MouseRegion(
cursor: SystemMouseCursors.click,
onEnter: (e) => setState(() => hover = true),
onExit: (e) => setState(() => hover = false),
child: GestureDetector(
onTap: () async {
if (await canLaunchUrlString(widget.message.message)) {
launchUrlString(widget.message.message);
}
},
child: AnimatedContainer(
child: GestureDetector(
onTap: () async {
if (await canLaunchUrlString(widget.message.message)) {
launchUrlString(widget.message.message);
}
},
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 4.0),
child: AnimatedSwitcher(
duration: const Duration(milliseconds: 250),
decoration: BoxDecoration(
color: hover
? Colors.grey.withOpacity(
currentStyleMode == AppStyle.dark ? 0.1 : 0.2)
: Colors.transparent,
borderRadius: BorderRadius.circular(20),
child: FutureBuilder(
future: _getMetaData(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return MouseRegion(
cursor: SystemMouseCursors.click,
child: UrlCard(
key: const ValueKey("url-card"),
url: widget.message.message,
dataMap: snapshot.data!.toMap()),
);
}
return MouseRegion(
cursor: SystemMouseCursors.click,
onEnter: (e) => setState(() => hover = true),
onExit: (e) => setState(() => hover = false),
child: AnimatedContainer(
key: const ValueKey("text-card"),
width: snapshot.hasError ? null : 400,
height: snapshot.hasError ? null : 300,
duration: const Duration(milliseconds: 250),
decoration: BoxDecoration(
color: hover
? Colors.grey.withOpacity(
currentStyleMode == AppStyle.dark ? 0.1 : 0.2)
: Colors.transparent,
borderRadius: BorderRadius.circular(20),
),
child: AppUtils.buildTooltip(
text: "Click to Open URl",
child: AnimatedTextKit(
animatedTexts: [
ColorizeAnimatedText(
widget.message.message,
colors: [
Colors.greenAccent,
Colors.cyan,
Colors.pinkAccent,
],
textStyle: TextStyle(
fontWeight: FontWeight.bold,
fontFamily: "Sen",
fontSize: 15,
color: currentStyleMode == AppStyle.dark
? Colors.greenAccent
: Colors.greenAccent.shade700),
),
],
repeatForever: !snapshot.hasError,
),
),
),
);
}),
),
),
),
);
}
}

class UrlCard extends StatelessWidget {
const UrlCard({super.key, required this.dataMap, required this.url});

final Map<String, String?> dataMap;
final String url;

@override
Widget build(BuildContext context) {
ImageProvider<Object>? image;
if (retrievedUrlsImageCache.containsKey(url)) {
image = retrievedUrlsImageCache[url];
} else {
image = NetworkImage(dataMap['image']!);
retrievedUrlsImageCache.putIfAbsent(url, () => image!);
}
return Container(
width: 400,
height: 300,
decoration: BoxDecoration(
color: currentStyle.getBackground(),
borderRadius: BorderRadius.circular(30),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.2),
blurRadius: 8,
offset: const Offset(4, 4),
),
],
),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ClipRRect(
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(30), topRight: Radius.circular(30)),
child: Center(
child: Image(
image: image!,
fit: BoxFit.fitWidth,
),
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
dataMap['title']!,
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 14,
fontFamily: "Sen",
color: currentStyle.getTextColor().withOpacity(0.8)),
),
child: Padding(
padding:
const EdgeInsets.symmetric(horizontal: 8.0, vertical: 4.0),
child: AppUtils.buildTooltip(
text: "Click to Open URl",
),
Flexible(
child: AppUtils.buildTooltip(
text: dataMap['description'] ?? "No Description",
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
widget.message.message,
dataMap['description'] ?? dataMap['url']!,
overflow: TextOverflow.ellipsis,
maxLines: 2,
style: TextStyle(
fontSize: 16,
fontFamily: "Sen",
fontSize: 15,
color: currentStyleMode == AppStyle.dark
? Colors.greenAccent
: Colors.greenAccent.shade700),
color: currentStyle.getTextColor()),
),
),
),
),
),
],
),
);
}
Expand Down
36 changes: 34 additions & 2 deletions pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "5.7.1"
animated_text_kit:
dependency: "direct main"
description:
name: animated_text_kit
sha256: "37392a5376c9a1a503b02463c38bc0342ef814ddbb8f9977bc90f2a84b22fa92"
url: "https://pub.dev"
source: hosted
version: "4.2.2"
archive:
dependency: transitive
description:
Expand Down Expand Up @@ -209,6 +217,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "3.0.2"
csslib:
dependency: transitive
description:
name: csslib
sha256: b36c7f7e24c0bdf1bf9a3da461c837d1de64b9f8beb190c9011d8c72a3dfd745
url: "https://pub.dev"
source: hosted
version: "0.17.2"
cupertino_icons:
dependency: "direct main"
description:
Expand Down Expand Up @@ -336,6 +352,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "3.0.5"
html:
dependency: transitive
description:
name: html
sha256: "79d498e6d6761925a34ee5ea8fa6dfef38607781d2fa91e37523474282af55cb"
url: "https://pub.dev"
source: hosted
version: "0.15.2"
http:
dependency: "direct main"
description:
Expand Down Expand Up @@ -440,6 +464,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.8.0"
metadata_fetch:
dependency: "direct main"
description:
name: metadata_fetch
sha256: "2c79e69e71cbb051041da6a8a9dd3df0617db84482ab3f36b4952ff779b7580e"
url: "https://pub.dev"
source: hosted
version: "0.4.1"
mime:
dependency: transitive
description:
Expand Down Expand Up @@ -737,10 +769,10 @@ packages:
dependency: "direct main"
description:
name: string_validator
sha256: b419cf5d21d608522e6e7cafed4deb34b6f268c43df866e63c320bab98a08cf6
sha256: "50dd8ecf91db6a732f4a851eeae81ee12406eedc62d0da72f2d91a04a2d10dd8"
url: "https://pub.dev"
source: hosted
version: "1.0.0"
version: "0.3.0"
term_glyph:
dependency: transitive
description:
Expand Down
4 changes: 3 additions & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,13 @@ dependencies:
web_socket_channel: ^2.3.0
http: ^0.13.5
file_picker: ^5.2.5
string_validator: ^1.0.0
string_validator: ^0.3.0
lottie: ^2.2.0
network_info_plus: ^3.0.2
url_launcher: ^6.1.10
build_runner: ^2.3.3
metadata_fetch: ^0.4.1
animated_text_kit: ^4.2.2

dev_dependencies:
flutter_test:
Expand Down

0 comments on commit b73e597

Please sign in to comment.