I am trying to make a bookmark app that you can input a title and URL on a dailog and list these on ListTile. I can see passed value (title and URL) on ListTile now but I cannot open URL that is passed from the dialog yet. How can I open URL that I add on ListTile?
Here is the whole code
main.dart
void main() {
runApp(const BookmarkApp());
}
class BookmarkApp extends StatelessWidget {
const BookmarkApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Bookmark App',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
useMaterial3: true,
),
home: BookmarkListPage(text: '', url: '',),
);
}
}
class BookmarkListPage extends StatefulWidget {
BookmarkListPage({super.key, title, required this.text, required this.url});
String text;
String url;
final String title = 'Bookmark List';
@override
State<BookmarkListPage> createState() => _BookmarkListPageState();
}
class _BookmarkListPageState extends State<BookmarkListPage> {
List<String> bookmarkList = [];
List<String> bookmarkUrl = [];
_launchUrl() async {
var url = Uri.parse(bookmarkUrl as String);
if(await canLaunchUrl(url)) {
await launchUrl(url);
} else {
throw "Could not open $url";
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.white,
title: Text(widget.title),
bottom: PreferredSize(
child: Container(
height: 1,
color: Colors.black,
),
preferredSize: Size.fromHeight(1),
),
),
body: ListView.builder(
itemCount: bookmarkList.length,
itemBuilder: (context, index) {
return Card(
child: ListTile(
title: Text(bookmarkList[index]),
subtitle: Text(bookmarkUrl[index]),
// TODO if you tap the List, open the URL
onTap: _launchUrl,
),
);
},
),
// show dialog
floatingActionButton: FloatingActionButton(
shape: const CircleBorder(),
backgroundColor: Colors.blue,
onPressed: () async {
final (newBookmarkTitle, newBookmarkUrl) = await showDialog(
context: context,
builder: (_) {
return BookmarkDialog();
});
setState(() {
bookmarkList.add(newBookmarkTitle);
bookmarkUrl.add(newBookmarkUrl);
});
},
child: const Icon(
Icons.add,
color: Colors.white,
),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
dialog.dart
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class BookmarkDialog extends StatefulWidget {
const BookmarkDialog({super.key});
@override
BookMarkDialogState createState() => BookMarkDialogState();
}
class BookMarkDialogState extends State<BookmarkDialog> {
String bookmarkTitle = "";
String bookmarkUrl = "";
@override
Widget build(BuildContext context) {
return AlertDialog(
title: const Text('Add Bookmark'),
content: Column(
children: [
Text('Title'),
TextField(onChanged: (value) {
setState(() {
bookmarkTitle = value;
});
}),
Text('URL'),
TextField(
onChanged: (value) {
setState(() {
bookmarkUrl = value;
});
},
)
],
),
actions: <Widget>[
GestureDetector(
child: const Text('Cancel'),
onTap: () {
Navigator.pop(context);
},
),
GestureDetector(
child: const Text('Add'),
onTap: () {
Navigator.of(context).pop((bookmarkTitle, bookmarkUrl));
},
)
],
);
}
}