mobile_signal 0.0.1
mobile_signal: ^0.0.1 copied to clipboard
Check mobile signal strength.
example/lib/main.dart
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:mobile_signal/mobile_signal.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) => MaterialApp(
title: 'Mobile Signal Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
useMaterial3: true,
),
home: const SignalMonitorPage(),
);
}
class SignalMonitorPage extends StatefulWidget {
const SignalMonitorPage({super.key});
@override
State<SignalMonitorPage> createState() => _SignalMonitorPageState();
}
class _SignalMonitorPageState extends State<SignalMonitorPage> {
SignalData? _lastSignal;
bool _isMonitoring = false;
String _error = '';
StreamSubscription<SignalData>? _signalSubscription;
@override
void initState() {
super.initState();
_checkPermissionAndStartMonitoring();
}
@override
void dispose() {
_signalSubscription?.cancel();
super.dispose();
}
Future<void> _checkPermissionAndStartMonitoring() async {
bool isGranted = await MobileSignal.instance.checkPermissions();
if (!isGranted) {
isGranted = await _requestPermissions();
}
if (isGranted) {
_startMonitoring();
} else {
setState(() {
_error = 'Permissions are required to access phone status.';
});
}
}
Future<bool> _requestPermissions() async {
final hasPermission = await MobileSignal.instance.requestPermissions();
return hasPermission;
}
Future<void> _startMonitoring() async {
try {
await MobileSignal.instance.startBackgroundService(
showNotificationTitle: true,
showNotificationValues: true,
notificationChannelName: 'Notification channel',
notificationTitle: 'Mobile Signal',
notificationDescription: 'Active Monitor',
);
_signalSubscription = MobileSignal.instance.signalStream.listen(
(signal) {
setState(() {
_lastSignal = signal;
_isMonitoring = true;
_error = '';
});
},
onError: (error) {
setState(() {
_error = 'Error: $error';
_isMonitoring = false;
});
},
);
} catch (e) {
setState(() {
_error = 'Error starting monitoring: $e';
_isMonitoring = false;
});
}
}
Future<void> _stopMonitoring() async {
try {
await _signalSubscription?.cancel();
_signalSubscription = null;
await MobileSignal.instance.stopBackgroundService();
setState(() {
_isMonitoring = false;
_lastSignal = null;
});
} catch (e) {
setState(() {
_error = 'Error stopping monitoring: $e';
});
}
}
String _getFormattedTimestamp(int timestamp) {
try {
final date = DateTime.fromMillisecondsSinceEpoch(timestamp);
return '${date.hour.toString().padLeft(2, '0')}:'
'${date.minute.toString().padLeft(2, '0')}:'
'${date.second.toString().padLeft(2, '0')}';
} catch (e) {
return 'Invalid timestamp';
}
}
Widget _buildSignalIndicator(int level) => Container(
width: 140,
padding: const EdgeInsets.all(8),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisSize: MainAxisSize.min,
children: List.generate(
4,
(index) => Container(
width: 8,
height: 12 + (index * 4),
margin:
const EdgeInsets.symmetric(horizontal: 1, vertical: 2),
decoration: BoxDecoration(
color: index < level ? Colors.blue : Colors.grey.shade300,
borderRadius: BorderRadius.circular(2),
),
)),
),
);
Widget _buildMetricCard(String title, String value, {String? subtitle}) =>
SizedBox(
width: 140,
child: Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
children: [
Text(
title,
style: TextStyle(
fontSize: 14,
color: Colors.grey.shade600,
),
),
const SizedBox(height: 8),
Text(
value,
style: const TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
),
),
if (subtitle != null) ...[
const SizedBox(height: 4),
Text(
subtitle,
style: TextStyle(
fontSize: 12,
color: Colors.grey.shade600,
),
),
],
],
),
),
),
);
Widget _buildSignalInfo() {
if (!_isMonitoring) {
return const SizedBox.shrink();
}
if (_lastSignal == null && _isMonitoring) {
return const Card(
child: Padding(
padding: EdgeInsets.all(16),
child: Text(
'Waiting for signal data...',
textAlign: TextAlign.center,
),
),
);
}
return Column(
children: [
Row(
children: [
Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
children: [
_buildSignalIndicator(_lastSignal!.level),
Text(
'Last update: ${_getFormattedTimestamp(_lastSignal!.ts)}',
style: Theme.of(context).textTheme.bodySmall,
),
],
),
),
),
const SizedBox(width: 16),
_buildNetworkInfo('Network', _lastSignal?.network),
],
),
const SizedBox(height: 16),
Row(
children: [
Expanded(
child: _buildMetricCard(
'Signal strength',
'${_lastSignal!.dbm}',
subtitle: 'dBm',
),
),
const SizedBox(width: 16),
Expanded(
child: _buildMetricCard(
'ASU Level',
'${_lastSignal!.asu}',
subtitle: 'Arbitrary Strength Unit',
),
),
],
),
],
);
}
@override
Widget build(BuildContext context) => Scaffold(
appBar: AppBar(
title: const Text('Mobile Signal Monitor'),
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
actions: [
IconButton(
icon: Icon(_isMonitoring ? Icons.stop : Icons.play_arrow),
onPressed: _isMonitoring ? _stopMonitoring : _startMonitoring,
),
],
),
body: SafeArea(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
if (_error.isNotEmpty)
Card(
color: Colors.red.shade100,
child: Padding(
padding: const EdgeInsets.all(16),
child: Row(
children: [
Icon(Icons.error_outline, color: Colors.red.shade700),
const SizedBox(width: 8),
Expanded(
child: Text(
_error,
style: TextStyle(color: Colors.red.shade700),
),
),
],
),
),
),
const SizedBox(height: 16),
_buildSignalInfo(),
const Spacer(),
ElevatedButton.icon(
onPressed: _isMonitoring ? _stopMonitoring : _startMonitoring,
icon: Icon(_isMonitoring ? Icons.stop : Icons.play_arrow),
label: Text(
_isMonitoring ? 'Stop Monitoring' : 'Start Monitoring'),
),
],
),
),
),
);
Widget _buildNetworkInfo(String title, String? value) => Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: SizedBox(
width: 140,
child: Column(
children: [
Text(
title,
style: TextStyle(
fontSize: 14,
color: Colors.grey.shade600,
),
),
const SizedBox(height: 8),
Text(
value ?? 'N/A',
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 4),
Text(
'isAirplane: ${_lastSignal?.isAirplane ?? false}',
style: TextStyle(
fontSize: 12,
color: Colors.grey.shade600,
),
),
],
),
),
),
);
}