ridu
unknown
dart
2 years ago
8.5 kB
4
Indexable
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
void main() => runApp(MyBrowserApp());
class MyBrowserApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Simple Browser',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: BrowserPage(),
);
}
}
class BrowserPage extends StatefulWidget {
@override
_BrowserPageState createState() => _BrowserPageState();
}
class _BrowserPageState extends State<BrowserPage> {
final TextEditingController _controller = TextEditingController();
List<WebViewController> _tabs = [];
List<String> _titles = [];
int _currentTabIndex = 0;
bool _showHomePage = true;
@override
void initState() {
super.initState();
_addNewTab(showHomePage: true);
}
void _addNewTab({bool showHomePage = false}) {
WebViewController webViewController = WebViewController()
..setJavaScriptMode(JavaScriptMode.unrestricted)
..setNavigationDelegate(NavigationDelegate(
onProgress: (int progress) {},
onPageStarted: (String url) {
_updateLoading(url);
_updateTitle('Loading...', _currentTabIndex);
},
onPageFinished: (String url) {
_updatePageTitle(_currentTabIndex);
},
onWebResourceError: (WebResourceError error) {},
onNavigationRequest: (NavigationRequest request) {
return NavigationDecision.navigate;
},
));
setState(() {
_tabs.add(webViewController);
_titles.add('New Tab');
_currentTabIndex = _tabs.length - 1;
_showHomePage = showHomePage;
});
}
@override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: _onWillPop,
child: Scaffold(
appBar: AppBar(
title: _showHomePage
? Text('Homepage')
: TextField(
controller: _controller,
decoration: InputDecoration(hintText: 'Enter a URL or search'),
onSubmitted: (input) => _loadSearch(input),
),
),
body: _showHomePage ? buildHomePage() : WebViewWidget(controller: _tabs[_currentTabIndex]),
bottomNavigationBar: buildBottomNavigationBar(),
),
);
}
Widget buildHomePage() {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: TextField(
decoration: InputDecoration(
hintText: 'Enter a URL or search',
border: OutlineInputBorder(),
),
onSubmitted: (input) => _loadSearch(input),
),
),
Wrap(
spacing: 10.0,
children: <Widget>[
_quickAccessButton('Facebook', 'https://facebook.com'),
_quickAccessButton('Twitter', 'https://twitter.com'),
_quickAccessButton('YouTube', 'https://youtube.com'),
_quickAccessButton('Gmail', 'https://mail.google.com'),
],
),
],
),
);
}
Widget _quickAccessButton(String name, String url) {
return ElevatedButton(
onPressed: () => _loadUrl(url),
child: Text(name),
);
}
void _loadSearch(String input) {
if (_isValidUrl(input)) {
_loadUrl(input.contains('://') ? input : 'https://$input');
} else {
_loadUrl('https://www.google.com/search?q=${Uri.encodeComponent(input)}');
}
}
void _loadUrl(String url) {
final Uri uri = Uri.parse(url);
if (uri.scheme.contains('http')) {
_tabs[_currentTabIndex].loadRequest(Uri.parse(url));
setState(() => _showHomePage = false);
}
}
bool _isValidUrl(String url) {
final Uri? uri = Uri.tryParse(url);
return uri != null && (uri.scheme == 'http' || uri.scheme == 'https');
}
BottomNavigationBar buildBottomNavigationBar() {
return BottomNavigationBar(
backgroundColor: Colors.white,
selectedItemColor: Colors.black,
unselectedItemColor: Colors.black,
items: <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.arrow_back),
label: 'Back',
),
BottomNavigationBarItem(
icon: Icon(Icons.arrow_forward),
label: 'Forward',
),
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: 'Home',
),
BottomNavigationBarItem(
icon: Icon(Icons.refresh),
label: 'Reload',
),
BottomNavigationBarItem(
icon: Icon(Icons.tab),
label: 'Tabs',
),
],
onTap: (index) => _handleNavBarTap(index),
);
}
void _handleNavBarTap(int index) {
if (index == 4) {
_showTabDialog();
} else {
switch (index) {
case 0: // Back
_handleBack();
break;
case 1: // Forward
_tabs[_currentTabIndex].goForward();
break;
case 2: // Home
setState(() => _showHomePage = true);
break;
case 3: // Reload
_tabs[_currentTabIndex].reload();
break;
}
}
}
Future<void> _handleBack() async {
if (await _tabs[_currentTabIndex].canGoBack()) {
_tabs[_currentTabIndex].goBack();
} else {
setState(() => _showHomePage = true);
}
}
void _showTabDialog() {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text('Open Tabs'),
content: Container(
width: double.maxFinite,
child: ListView.builder(
itemCount: _tabs.length,
itemBuilder: (BuildContext context, int index) {
return ListTile(
title: Text('Tab ${index + 1} - ${_titles[index]}'),
trailing: index != _currentTabIndex ? IconButton(
icon: Icon(Icons.close),
onPressed: () => _closeTab(index),
) : null,
onTap: () {
setState(() {
_currentTabIndex = index;
_showHomePage = false;
});
Navigator.of(context).pop();
},
);
},
),
),
actions: <Widget>[
TextButton(
child: Text('New Tab'),
onPressed: () {
Navigator.of(context).pop();
_addNewTab(showHomePage: true);
},
),
],
);
},
);
}
void _closeTab(int index) {
if (_tabs.length > 1) {
setState(() {
_tabs.removeAt(index);
_titles.removeAt(index);
_currentTabIndex = 0; // Switch to the first tab
_showHomePage = true;
});
}
Navigator.of(context).pop();
}
void _updateLoading(String url) {
setState(() {
_controller.text = url;
_showHomePage = false;
});
}
void _updatePageTitle(int tabIndex) {
_tabs[tabIndex].runJavaScriptReturningResult('document.title').then((result) {
String title = result is String ? result : 'No Title';
setState(() {
_titles[tabIndex] = title;
});
});
}
void _updateTitle(String title, int tabIndex) {
setState(() {
_titles[tabIndex] = title;
});
}
Future<bool> _onWillPop() async {
if (!_showHomePage) {
if (await _tabs[_currentTabIndex].canGoBack()) {
_tabs[_currentTabIndex].goBack();
return false; // Prevent exiting the app
} else {
setState(() => _showHomePage = true);
return false; // Prevent exiting the app
}
} else {
return (await showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text('Exit Browser'),
content: Text('Are you sure you want to exit the browser?'),
actions: <Widget>[
TextButton(
child: Text('No'),
onPressed: () => Navigator.of(context).pop(false),
),
TextButton(
child: Text('Yes'),
onPressed: () => Navigator.of(context).pop(true),
),
],
),
)) ?? false;
}
}
}
Editor is loading...
Leave a Comment