appcare_flutter 2.0.0
appcare_flutter: ^2.0.0 copied to clipboard
An all-in-one Flutter utility package for app maintenance, upgrader dialogs, device info, battery, network diagnostics, biometrics, security, and hardware controls.
example/lib/main.dart
import 'package:flutter/material.dart';
import 'package:appcare_flutter/appcare_flutter.dart';
void main() {
runApp(const UpgradeAlert(child: AppCareExampleApp()));
}
class AppCareExampleApp extends StatefulWidget {
const AppCareExampleApp({super.key});
@override
State<AppCareExampleApp> createState() => _AppCareExampleAppState();
}
class _AppCareExampleAppState extends State<AppCareExampleApp> {
ThemeMode _themeMode = ThemeMode.system;
void _toggleTheme() {
setState(() {
_themeMode = _themeMode == ThemeMode.dark
? ThemeMode.light
: ThemeMode.dark;
});
}
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'AppCare Flutter Showcase',
debugShowCheckedModeBanner: false,
themeMode: _themeMode,
theme: ThemeData(
useMaterial3: true,
colorSchemeSeed: const Color(0xFF6366F1), // Modern Indigo
brightness: Brightness.light,
cardTheme: CardThemeData(
elevation: 0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
side: BorderSide(color: Colors.grey.shade200),
),
),
),
darkTheme: ThemeData(
useMaterial3: true,
colorSchemeSeed: const Color(0xFF6366F1),
brightness: Brightness.dark,
cardTheme: CardThemeData(
elevation: 0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
side: BorderSide(color: Colors.grey.shade800),
),
),
),
home: ShowcaseHomeScreen(
isDark: _themeMode == ThemeMode.dark,
onToggleTheme: _toggleTheme,
),
);
}
}
class ShowcaseHomeScreen extends StatefulWidget {
final bool isDark;
final VoidCallback onToggleTheme;
const ShowcaseHomeScreen({
super.key,
required this.isDark,
required this.onToggleTheme,
});
@override
State<ShowcaseHomeScreen> createState() => _ShowcaseHomeScreenState();
}
class _ShowcaseHomeScreenState extends State<ShowcaseHomeScreen>
with SingleTickerProviderStateMixin {
final _appCare = AppCare();
late TabController _tabController;
// Diagnostics State
bool _isConnected = true;
NetworkType _netType = NetworkType.none;
AppBaseInfo? _appInfo;
DeviceInfo? _deviceInfo;
GeoLocation? _location;
BatteryInfo? _batteryInfo;
StorageInfo? _storageInfo;
AppLaunchInfo? _launchInfo;
ThermalStatus _thermal = ThermalStatus.normal;
bool _isLowRam = false;
bool _isSystemDark = false;
String _locale = '...';
int _pingMs = -1;
String _localIp = '...';
int _wifiSignal = 0;
// Security & Controls State
bool _isSecurityEnabled = false;
bool _keepScreenOn = false;
double _volume = 1.0;
bool _isMuted = false;
bool _hasBiometrics = false;
double _fontScale = 1.0;
bool _isMockLoc = false;
bool _isAutoTime = true;
bool _isScreenRecording = false;
bool _hasWhatsApp = false;
bool _isTorchOn = false;
bool _isLoading = false;
@override
void initState() {
super.initState();
_tabController = TabController(length: 4, vsync: this);
_initListeners();
_loadAllData();
}
@override
void dispose() {
_tabController.dispose();
super.dispose();
}
void _initListeners() {
_appCare.checkConnectivity().then((value) {
if (mounted) setState(() => _isConnected = value);
});
_appCare.onConnectivityChanged.listen((status) {
if (mounted) {
setState(() => _isConnected = status);
_showSnackBar(
status ? 'Network connection restored' : 'Network connection lost',
isError: !status,
);
}
});
}
Future<void> _loadAllData() async {
setState(() => _isLoading = true);
try {
final appInfo = await _appCare.getAppBaseInfo();
final deviceInfo = await _appCare.getDeviceInfo();
final battery = await _appCare.getBatteryInfo();
final storage = await _appCare.getStorageInfo();
final netType = await _appCare.getNetworkType();
final locale = await _appCare.getDeviceLocale();
final launch = await _appCare.getAppLaunchInfo();
final thermal = await _appCare.getThermalStatus();
final lowRam = await _appCare.isLowMemory();
final dark = await _appCare.isDarkMode();
final volume = await _appCare.getVolume();
final muted = await _appCare.isMuted();
final ip = await _appCare.getLocalIpAddress();
final bio = await _appCare.canAuthenticateBiometrics();
final fontScale = await _appCare.getFontScale();
final ping = await _appCare.pingHost();
final mockLoc = await _appCare.isMockLocation();
final autoTime = await _appCare.isAutomaticTime();
final recording = await _appCare.isScreenBeingRecorded();
final whatsApp = await _appCare.isAppInstalled('com.whatsapp');
final wifiSignal = await _appCare.getWifiSignalStrength();
if (mounted) {
setState(() {
_appInfo = appInfo;
_deviceInfo = deviceInfo;
_batteryInfo = battery;
_storageInfo = storage;
_netType = netType;
_locale = locale;
_launchInfo = launch;
_thermal = thermal;
_isLowRam = lowRam;
_isSystemDark = dark;
_volume = volume;
_isMuted = muted;
_localIp = ip ?? 'Unavailable';
_hasBiometrics = bio;
_fontScale = fontScale;
_pingMs = ping;
_isMockLoc = mockLoc;
_isAutoTime = autoTime;
_isScreenRecording = recording;
_hasWhatsApp = whatsApp;
_wifiSignal = wifiSignal;
_isLoading = false;
});
}
} catch (_) {
if (mounted) setState(() => _isLoading = false);
}
}
void _showSnackBar(String message, {bool isError = false}) {
if (!mounted) return;
ScaffoldMessenger.of(context).hideCurrentSnackBar();
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(message),
backgroundColor: isError ? Colors.redAccent : const Color(0xFF6366F1),
behavior: SnackBarBehavior.floating,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
),
);
}
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
return Scaffold(
appBar: AppBar(
title: Row(
children: [
Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: theme.colorScheme.primaryContainer,
borderRadius: BorderRadius.circular(10),
),
child: Icon(
Icons.shield_outlined,
color: theme.colorScheme.primary,
size: 22,
),
),
const SizedBox(width: 12),
const Text(
'AppCare Showcase',
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 18),
),
],
),
actions: [
IconButton(
icon: Icon(widget.isDark ? Icons.light_mode : Icons.dark_mode),
tooltip: 'Toggle Theme',
onPressed: widget.onToggleTheme,
),
IconButton(
icon: _isLoading
? const SizedBox(
width: 18,
height: 18,
child: CircularProgressIndicator(strokeWidth: 2),
)
: const Icon(Icons.refresh),
tooltip: 'Refresh Data',
onPressed: _loadAllData,
),
],
bottom: TabBar(
controller: _tabController,
isScrollable: true,
labelPadding: const EdgeInsets.symmetric(horizontal: 16),
indicatorColor: theme.colorScheme.primary,
labelColor: theme.colorScheme.primary,
unselectedLabelColor: Colors.grey,
tabs: const [
Tab(icon: Icon(Icons.analytics_outlined), text: 'Diagnostics'),
Tab(icon: Icon(Icons.security_outlined), text: 'Anti-Cheat'),
Tab(icon: Icon(Icons.tune_outlined), text: 'Hardware'),
Tab(icon: Icon(Icons.system_update_outlined), text: 'Launchers'),
],
),
),
body: RefreshIndicator(
onRefresh: _loadAllData,
child: TabBarView(
controller: _tabController,
children: [
_buildDiagnosticsTab(),
_buildSecurityTab(),
_buildHardwareTab(),
_buildLaunchersTab(),
],
),
),
);
}
// -------------------------------------------------------------
// TAB 1: DIAGNOSTICS & SYSTEM STATS
// -------------------------------------------------------------
Widget _buildDiagnosticsTab() {
return ListView(
padding: const EdgeInsets.all(16),
children: [
// Live Network Banner
Container(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14),
decoration: BoxDecoration(
color: _isConnected
? Colors.green.withValues(alpha: 0.1)
: Colors.red.withValues(alpha: 0.1),
borderRadius: BorderRadius.circular(16),
border: Border.all(
color: _isConnected
? Colors.green.withValues(alpha: 0.3)
: Colors.red.withValues(alpha: 0.3),
),
),
child: Row(
children: [
Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: _isConnected ? Colors.green : Colors.red,
shape: BoxShape.circle,
),
child: Icon(
_isConnected ? Icons.wifi : Icons.wifi_off,
color: Colors.white,
size: 18,
),
),
const SizedBox(width: 12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
_isConnected
? 'Connected (${_netType.name.toUpperCase()})'
: 'No Internet Connection',
style: TextStyle(
fontWeight: FontWeight.bold,
color: _isConnected
? Colors.green.shade800
: Colors.red,
),
),
Text(
'Ping: ${_pingMs >= 0 ? "${_pingMs}ms" : "N/A"} | Wi-Fi Level: $_wifiSignal/4 | IP: $_localIp',
style: TextStyle(
fontSize: 12,
color: Colors.grey.shade700,
),
),
],
),
),
],
),
),
const SizedBox(height: 16),
// Battery & Storage Summary Grid
Row(
children: [
Expanded(
child: Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Icon(
Icons.battery_charging_full,
color: Colors.green,
),
Text(
'${_batteryInfo?.batteryLevel ?? -1}%',
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
],
),
const SizedBox(height: 8),
LinearProgressIndicator(
value: (_batteryInfo?.batteryLevel ?? 0) / 100,
backgroundColor: Colors.grey.withValues(alpha: 0.2),
color: Colors.green,
borderRadius: BorderRadius.circular(4),
),
const SizedBox(height: 6),
Text(
_batteryInfo?.isCharging == true
? '⚡ Charging'
: 'Discharging',
style: const TextStyle(
fontSize: 11,
color: Colors.grey,
),
),
],
),
),
),
),
const SizedBox(width: 12),
Expanded(
child: Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Icon(
Icons.storage_outlined,
color: Colors.deepPurple,
),
Text(
_storageInfo != null
? '${_storageInfo!.freeGB.toStringAsFixed(1)} GB'
: '...',
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
],
),
const SizedBox(height: 8),
LinearProgressIndicator(
value:
_storageInfo != null && _storageInfo!.totalBytes > 0
? _storageInfo!.freeBytes / _storageInfo!.totalBytes
: 0.5,
backgroundColor: Colors.grey.withValues(alpha: 0.2),
color: Colors.deepPurple,
borderRadius: BorderRadius.circular(4),
),
const SizedBox(height: 6),
Text(
'Total: ${_storageInfo != null ? "${_storageInfo!.totalGB.toStringAsFixed(1)} GB" : "..."}',
style: const TextStyle(
fontSize: 11,
color: Colors.grey,
),
),
],
),
),
),
),
],
),
const SizedBox(height: 16),
// Device & Package Details
_buildSectionCard(
title: 'Device & OS Specs',
icon: Icons.phone_android_outlined,
children: [
_buildDataRow(
'Model',
'${_deviceInfo?.manufacturer} ${_deviceInfo?.model}',
),
_buildDataRow(
'OS',
'${_deviceInfo?.osName} ${_deviceInfo?.osVersion}',
),
_buildDataRow(
'RAM Memory',
_isLowRam ? 'Low Memory Pressure' : 'Normal',
),
_buildDataRow('Thermal State', _thermal.name.toUpperCase()),
_buildDataRow('Font Scale', '${_fontScale.toStringAsFixed(2)}x'),
_buildDataRow(
'System Theme',
_isSystemDark ? 'Dark Mode' : 'Light Mode',
),
],
),
const SizedBox(height: 16),
// App Launch & Package Specs
_buildSectionCard(
title: 'App Package & Session',
icon: Icons.info_outline,
children: [
_buildDataRow('App Name', _appInfo?.appName ?? '...'),
_buildDataRow('Package ID', _appInfo?.packageName ?? '...'),
_buildDataRow(
'Version',
'${_appInfo?.version ?? "..."}+${_appInfo?.buildNumber ?? "..."}',
),
_buildDataRow('Locale', _locale),
_buildDataRow(
'First Launch',
_launchInfo?.isFirstLaunch == true ? 'Yes' : 'No',
),
_buildDataRow(
'Post Update',
_launchInfo?.isFirstLaunchAfterUpdate == true ? 'Yes' : 'No',
),
_buildDataRow(
'Session Uptime',
'${_launchInfo?.sessionUptimeSeconds ?? 0} seconds',
),
],
),
],
);
}
// -------------------------------------------------------------
// TAB 2: SECURITY & ANTI-CHEAT
// -------------------------------------------------------------
Widget _buildSecurityTab() {
return ListView(
padding: const EdgeInsets.all(16),
children: [
_buildSectionCard(
title: 'Anti-Cheat & Environmental Integrity',
icon: Icons.gpp_good_outlined,
children: [
_buildStatusTile(
title: 'Fake GPS / Mock Location',
subtitle: 'Detects mock location mocking apps',
status: _isMockLoc ? 'DETECTED' : 'CLEAN',
isWarning: _isMockLoc,
icon: Icons.location_off_outlined,
),
_buildStatusTile(
title: 'Network Time Sync',
subtitle: 'Prevents device time tampering',
status: _isAutoTime ? 'SYNCED' : 'MANUAL CLOCK',
isWarning: !_isAutoTime,
icon: Icons.access_time_outlined,
),
_buildStatusTile(
title: 'Active Screen Recording',
subtitle: 'Monitors ongoing screen recording/casting',
status: _isScreenRecording ? 'RECORDING' : 'OFF',
isWarning: _isScreenRecording,
icon: Icons.videocam_outlined,
),
_buildStatusTile(
title: 'WhatsApp Detection',
subtitle: 'Checks external app installation',
status: _hasWhatsApp ? 'INSTALLED' : 'NOT FOUND',
isWarning: false,
icon: Icons.chat_bubble_outline,
),
],
),
const SizedBox(height: 16),
_buildSectionCard(
title: 'Screen Privacy Controls',
icon: Icons.lock_outline,
children: [
SwitchListTile(
title: const Text('Block Screenshots & Recording'),
subtitle: Text(
_isSecurityEnabled
? 'Protected (Screenshots blocked)'
: 'Disabled (Screenshots allowed)',
style: const TextStyle(fontSize: 12),
),
value: _isSecurityEnabled,
onChanged: (val) async {
final ok = await _appCare.setScreenSecurity(enable: val);
if (ok && mounted) {
setState(() => _isSecurityEnabled = val);
_showSnackBar(
val
? 'Screenshot blocking enabled'
: 'Screenshot blocking disabled',
);
}
},
),
],
),
const SizedBox(height: 16),
// Geo Location Card
_buildSectionCard(
title: 'GPS Coordinates',
icon: Icons.my_location_outlined,
trailing: ElevatedButton.icon(
onPressed: () async {
final loc = await _appCare.getCurrentLocation();
if (mounted) {
setState(() => _location = loc);
_showSnackBar(
loc != null
? 'Location fetched: ${loc.latitude}, ${loc.longitude}'
: 'Location unavailable',
);
}
},
icon: const Icon(Icons.gps_fixed, size: 16),
label: const Text('Get Location'),
),
children: [
_buildDataRow(
'Latitude',
_location != null ? '${_location!.latitude}' : 'N/A',
),
_buildDataRow(
'Longitude',
_location != null ? '${_location!.longitude}' : 'N/A',
),
],
),
],
);
}
// -------------------------------------------------------------
// TAB 3: HARDWARE & CONTROLS
// -------------------------------------------------------------
Widget _buildHardwareTab() {
return ListView(
padding: const EdgeInsets.all(16),
children: [
// Flashlight & WakeLock Quick Toggles
Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Hardware Toggles',
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
),
const SizedBox(height: 12),
Row(
children: [
Expanded(
child: OutlinedButton.icon(
onPressed: () async {
final success = await _appCare.toggleFlashlight();
if (success && mounted) {
setState(() => _isTorchOn = !_isTorchOn);
_showSnackBar(
_isTorchOn ? 'Flashlight ON' : 'Flashlight OFF',
);
}
},
icon: Icon(
_isTorchOn ? Icons.flash_off : Icons.flash_on,
color: _isTorchOn ? Colors.orange : null,
),
label: Text(_isTorchOn ? 'Torch OFF' : 'Torch ON'),
),
),
const SizedBox(width: 12),
Expanded(
child: OutlinedButton.icon(
onPressed: () async {
final newVal = !_keepScreenOn;
final ok = await _appCare.setKeepScreenOn(
keepOn: newVal,
);
if (ok && mounted) {
setState(() => _keepScreenOn = newVal);
_showSnackBar(
newVal
? 'Screen WakeLock ON'
: 'Screen WakeLock OFF',
);
}
},
icon: Icon(
_keepScreenOn
? Icons.visibility
: Icons.visibility_off,
color: _keepScreenOn ? Colors.blue : null,
),
label: Text(_keepScreenOn ? 'Awake ON' : 'Awake OFF'),
),
),
],
),
],
),
),
),
const SizedBox(height: 16),
// Biometrics Hardware Status
_buildSectionCard(
title: 'Biometrics Security',
icon: Icons.fingerprint_outlined,
children: [
_buildStatusTile(
title: 'Biometric Hardware Enrolled',
subtitle: 'Fingerprint / Face ID availability',
status: _hasBiometrics ? 'ENROLLED' : 'NOT ENROLLED',
isWarning: !_hasBiometrics,
icon: Icons.fingerprint,
),
],
),
const SizedBox(height: 16),
// Haptic Feedback Presets
_buildSectionCard(
title: 'Haptic Vibration Engine',
icon: Icons.vibration_outlined,
children: [
const Padding(
padding: EdgeInsets.only(bottom: 12),
child: Text(
'Test native haptic tactile feedback patterns:',
style: TextStyle(fontSize: 13, color: Colors.grey),
),
),
Wrap(
spacing: 8,
runSpacing: 8,
children: [
_buildHapticChip('Light', HapticType.light),
_buildHapticChip('Medium', HapticType.medium),
_buildHapticChip('Heavy', HapticType.heavy),
_buildHapticChip('Selection', HapticType.selection),
_buildHapticChip('Success', HapticType.success),
_buildHapticChip('Error', HapticType.error),
],
),
],
),
const SizedBox(height: 16),
// Audio & Volume
_buildSectionCard(
title: 'Audio & Volume Controller',
icon: Icons.volume_up_outlined,
children: [
Row(
children: [
Icon(_isMuted ? Icons.volume_off : Icons.volume_up),
const SizedBox(width: 8),
Expanded(
child: Slider(
value: _volume.clamp(0.0, 1.0),
min: 0.0,
max: 1.0,
divisions: 10,
label: '${(_volume * 100).toInt()}%',
onChanged: (val) async {
setState(() => _volume = val);
await _appCare.setVolume(val);
},
),
),
Text('${(_volume * 100).toInt()}%'),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Silent Mode: ${_isMuted ? "Muted" : "Active"}',
style: const TextStyle(fontSize: 13),
),
TextButton.icon(
onPressed: () async {
await _appCare.playSystemBeep();
_showSnackBar('Played system audio feedback');
},
icon: const Icon(Icons.music_note, size: 16),
label: const Text('Play Beep'),
),
],
),
],
),
const SizedBox(height: 16),
// Screen Orientation
_buildSectionCard(
title: 'Screen Orientation Controls',
icon: Icons.screen_rotation_outlined,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
ElevatedButton.icon(
onPressed: () =>
_appCare.setOrientation(ScreenOrientation.portrait),
icon: const Icon(Icons.stay_current_portrait, size: 16),
label: const Text('Portrait'),
),
ElevatedButton.icon(
onPressed: () =>
_appCare.setOrientation(ScreenOrientation.landscape),
icon: const Icon(Icons.stay_current_landscape, size: 16),
label: const Text('Landscape'),
),
OutlinedButton.icon(
onPressed: () =>
_appCare.setOrientation(ScreenOrientation.unlock),
icon: const Icon(Icons.screen_rotation, size: 16),
label: const Text('Unlock'),
),
],
),
],
),
],
);
}
// -------------------------------------------------------------
// TAB 4: LAUNCHERS & MAINTENANCE
// -------------------------------------------------------------
Widget _buildLaunchersTab() {
return ListView(
padding: const EdgeInsets.all(16),
children: [
// Upgrader Widget Live Preview
const UpgradeCard(elevation: 0, title: 'In-App Update Status'),
const SizedBox(height: 16),
// In-App Rating & Review
_buildSectionCard(
title: 'In-App Rating & Review',
icon: Icons.star_rate_outlined,
children: [
const Text(
'Triggers native in-app review popup with 7-day cooldown logic.',
style: TextStyle(fontSize: 13, color: Colors.grey),
),
const SizedBox(height: 12),
Row(
children: [
Expanded(
child: ElevatedButton.icon(
onPressed: () async {
final prompted = await _appCare.requestReview(
minDaysBeforePrompt: 7,
);
_showSnackBar(
prompted
? 'Review prompt triggered!'
: 'Review prompt skipped (cooldown active)',
);
},
icon: const Icon(Icons.rate_review, size: 16),
label: const Text('Prompt Review'),
),
),
const SizedBox(width: 12),
OutlinedButton(
onPressed: () async {
await _appCare.resetReviewHistory();
_showSnackBar('Review cooldown history cleared');
},
child: const Text('Reset Cooldown'),
),
],
),
],
),
const SizedBox(height: 16),
// Native Launchers Grid
_buildSectionCard(
title: 'Native App & URL Launchers',
icon: Icons.launch_outlined,
children: [
_buildLauncherRow(
icon: Icons.language,
title: 'Open Website URL',
subtitle: 'https://www.rahulreza.com',
onTap: () => _appCare.openUrl('https://www.rahulreza.com'),
),
_buildLauncherRow(
icon: Icons.email_outlined,
title: 'Send Support Email',
subtitle: 'contact@rahulreza.com',
onTap: () => _appCare.openEmail(
'contact@rahulreza.com',
subject: 'AppCare Support',
),
),
_buildLauncherRow(
icon: Icons.phone_outlined,
title: 'Open Phone Dialer',
subtitle: '+8801700000000',
onTap: () => _appCare.openDialer('+8801700000000'),
),
_buildLauncherRow(
icon: Icons.storefront_outlined,
title: 'Open App Store Listing',
subtitle: 'Opens native Play/App store',
onTap: () => _appCare.openStore(),
),
],
),
const SizedBox(height: 16),
// Clipboard & Badge Management
_buildSectionCard(
title: 'Clipboard & App Icon Badge',
icon: Icons.copy_outlined,
children: [
Row(
children: [
Expanded(
child: ElevatedButton.icon(
onPressed: () async {
await _appCare.copyToClipboard('Hello from AppCare!');
_showSnackBar('Copied "Hello from AppCare!"');
},
icon: const Icon(Icons.copy, size: 16),
label: const Text('Copy Text'),
),
),
const SizedBox(width: 12),
Expanded(
child: OutlinedButton.icon(
onPressed: () async {
final text = await _appCare.getTextFromClipboard();
_showSnackBar('Clipboard Content: $text');
},
icon: const Icon(Icons.paste, size: 16),
label: const Text('Read Text'),
),
),
],
),
const SizedBox(height: 12),
Row(
children: [
Expanded(
child: ElevatedButton.icon(
onPressed: () async {
await _appCare.setAppBadgeCount(5);
_showSnackBar('App icon badge set to 5');
},
icon: const Icon(Icons.mark_email_unread, size: 16),
label: const Text('Set Badge (5)'),
),
),
const SizedBox(width: 12),
OutlinedButton(
onPressed: () async {
await _appCare.clearAppBadge();
_showSnackBar('App icon badge cleared');
},
child: const Text('Clear Badge'),
),
],
),
],
),
],
);
}
// -------------------------------------------------------------
// HELPER WIDGETS
// -------------------------------------------------------------
Widget _buildSectionCard({
required String title,
required IconData icon,
required List<Widget> children,
Widget? trailing,
}) {
final theme = Theme.of(context);
return Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Icon(icon, color: theme.colorScheme.primary, size: 20),
const SizedBox(width: 8),
Text(
title,
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
],
),
if (trailing != null) trailing,
],
),
const Divider(height: 24),
...children,
],
),
),
);
}
Widget _buildDataRow(String label, String value) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 4),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(label, style: const TextStyle(fontSize: 13, color: Colors.grey)),
Text(
value,
style: const TextStyle(fontSize: 13, fontWeight: FontWeight.w600),
),
],
),
);
}
Widget _buildStatusTile({
required String title,
required String subtitle,
required String status,
required bool isWarning,
required IconData icon,
}) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 6),
child: Row(
children: [
Icon(icon, size: 20, color: Colors.grey),
const SizedBox(width: 12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.w600,
),
),
Text(
subtitle,
style: const TextStyle(fontSize: 11, color: Colors.grey),
),
],
),
),
Container(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4),
decoration: BoxDecoration(
color: isWarning
? Colors.red.withValues(alpha: 0.15)
: Colors.green.withValues(alpha: 0.15),
borderRadius: BorderRadius.circular(20),
),
child: Text(
status,
style: TextStyle(
fontSize: 11,
fontWeight: FontWeight.bold,
color: isWarning ? Colors.red : Colors.green,
),
),
),
],
),
);
}
Widget _buildHapticChip(String label, HapticType type) {
return ActionChip(
avatar: const Icon(Icons.touch_app, size: 14),
label: Text(label),
onPressed: () async {
await _appCare.vibrate(type: type);
_showSnackBar('Haptic: $label triggered');
},
);
}
Widget _buildLauncherRow({
required IconData icon,
required String title,
required String subtitle,
required VoidCallback onTap,
}) {
return ListTile(
contentPadding: EdgeInsets.zero,
leading: Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.primaryContainer,
borderRadius: BorderRadius.circular(8),
),
child: Icon(
icon,
size: 20,
color: Theme.of(context).colorScheme.primary,
),
),
title: Text(
title,
style: const TextStyle(fontSize: 14, fontWeight: FontWeight.bold),
),
subtitle: Text(
subtitle,
style: const TextStyle(fontSize: 12, color: Colors.grey),
),
trailing: const Icon(Icons.arrow_forward_ios, size: 14),
onTap: onTap,
);
}
}