merge from old repo

This commit is contained in:
Bartosz 2024-11-06 20:00:35 +00:00
parent 4359057c1d
commit 50235b13c5
15 changed files with 980 additions and 15 deletions

View File

@ -45,5 +45,8 @@
<true/>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
<key>NSContactsUsageDescription</key>
<string>Contacts for calls/string>
</dict>
</plist>

View File

@ -1,36 +1,152 @@
// history_page.dart
import 'package:flutter/material.dart';
import 'package:flutter_contacts/flutter_contacts.dart';
import 'package:intl/intl.dart'; // For date formatting
import 'package:dialer/features/contacts/contact_state.dart';
class History {
final Contact contact;
final DateTime date;
final String callType; // 'incoming' or 'outgoing'
final String callStatus; // 'missed' or 'answered'
final int attempts;
List<History> histories = [
History("Hello"),
];
History(
this.contact,
this.date,
this.callType,
this.callStatus,
this.attempts,
);
}
class HistoryPage extends StatefulWidget {
const HistoryPage({super.key});
const HistoryPage({Key? key}) : super(key: key);
@override
_HistoryPageState createState() => _HistoryPageState();
}
class _HistoryPageState extends State<HistoryPage> {
List<History> histories = [];
bool loading = true;
@override
void didChangeDependencies() {
super.didChangeDependencies();
if (loading) {
_buildHistories();
}
}
Future<void> _buildHistories() async {
final contactState = ContactState.of(context);
if (contactState.loading) {
// Wait for contacts to be loaded
await Future.doWhile(() async {
await Future.delayed(const Duration(milliseconds: 100));
return contactState.loading;
});
}
List<Contact> contacts = contactState.contacts;
// Ensure there are enough contacts
if (contacts.isEmpty) {
setState(() {
loading = false;
});
return;
}
// Build histories using the contacts
setState(() {
histories = List.generate(
contacts.length >= 10 ? 10 : contacts.length,
(index) => History(
contacts[index],
DateTime.now().subtract(Duration(hours: (index + 1) * 2)),
index % 2 == 0 ? 'outgoing' : 'incoming',
index % 3 == 0 ? 'missed' : 'answered',
index % 3 + 1,
),
);
loading = false;
});
}
@override
Widget build(BuildContext context) {
final contactState = ContactState.of(context);
if (loading || contactState.loading) {
return Scaffold(
backgroundColor: Colors.black,
appBar: AppBar(
title: const Text('History'),
),
body: const Center(
child: CircularProgressIndicator(),
),
);
}
if (histories.isEmpty) {
return Scaffold(
backgroundColor: Colors.black,
appBar: AppBar(
title: const Text('History'),
),
body: const Center(
child: Text(
'No call history available.',
style: TextStyle(color: Colors.white),
),
),
);
}
return Scaffold(
backgroundColor: Colors.black,
appBar: AppBar(
title: const Text('History'),
),
body: ListView.builder(
itemCount: histories.length,
itemBuilder: (context, index) {
return null;
//
final history = histories[index];
final contact = history.contact;
return ListTile(
leading: (contact.thumbnail != null && contact.thumbnail!.isNotEmpty)
? CircleAvatar(
backgroundImage: MemoryImage(contact.thumbnail!),
)
: CircleAvatar(
child: Text(
contact.displayName.isNotEmpty
? contact.displayName[0]
: '?',
),
),
title: Text(
contact.displayName,
style: const TextStyle(color: Colors.white),
),
subtitle: Text(
'${history.callType} - ${history.callStatus} - ${DateFormat('MMM dd, hh:mm a').format(history.date)}',
style: const TextStyle(color: Colors.grey),
),
trailing: Text(
'${history.attempts}x',
style: const TextStyle(color: Colors.white),
),
onTap: () {
// Handle tap event if needed
},
);
},
),
);
}
}
class History {
final String text;
History(this.text);
}

View File

@ -4,6 +4,7 @@ import 'package:dialer/features/favorites/favorites_page.dart';
import 'package:dialer/features/history/history_page.dart';
import 'package:dialer/features/composition/composition.dart';
import 'package:flutter_contacts/flutter_contacts.dart';
import 'package:dialer/features/settings/settings.dart';
class _MyHomePageState extends State<MyHomePage>
with SingleTickerProviderStateMixin {
@ -14,7 +15,7 @@ class _MyHomePageState extends State<MyHomePage>
@override
void initState() {
super.initState();
_tabController = TabController(length: 3, vsync: this, initialIndex: 1);
_tabController = TabController(length: 4, vsync: this, initialIndex: 1);
_tabController.addListener(_handleTabIndex);
_fetchContacts();
}
@ -83,7 +84,7 @@ class _MyHomePageState extends State<MyHomePage>
return SearchBar(
controller: controller,
padding: MaterialStateProperty.all<EdgeInsetsGeometry>(
EdgeInsets.only(
const EdgeInsets.only(
top: 6.0,
bottom: 6.0,
left: 16.0,
@ -141,6 +142,7 @@ class _MyHomePageState extends State<MyHomePage>
FavoritePage(),
HistoryPage(),
ContactPage(),
SettingsPage(), // Add your SettingsPage here
],
),
Positioned(
@ -184,6 +186,10 @@ class _MyHomePageState extends State<MyHomePage>
icon: Icon(_tabController.index == 2
? Icons.contacts
: Icons.contacts_outlined)),
Tab(
icon: Icon(_tabController.index == 3 // Corrected index
? Icons.settings
: Icons.settings_outlined)),
],
labelColor: Colors.white,
unselectedLabelColor: const Color.fromARGB(255, 158, 158, 158),

View File

@ -0,0 +1,92 @@
import 'package:flutter/material.dart';
class SettingsCallPage extends StatefulWidget {
const SettingsCallPage({super.key});
@override
_SettingsCallPageState createState() => _SettingsCallPageState();
}
class _SettingsCallPageState extends State<SettingsCallPage> {
bool _enableVoicemail = true;
bool _enableCallRecording = false;
String _ringtone = 'Default';
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.black,
appBar: AppBar(
title: const Text('Calling settings'),
),
body: ListView(
children: [
SwitchListTile(
title: const Text('Enable Voicemail', style: TextStyle(color: Colors.white)),
value: _enableVoicemail,
onChanged: (bool value) {
setState(() {
_enableVoicemail = value;
});
},
),
SwitchListTile(
title: const Text('Enable call Recording', style: TextStyle(color: Colors.white)),
value: _enableCallRecording,
onChanged: (bool value) {
setState(() {
_enableCallRecording = value;
});
},
),
ListTile(
title: const Text('Ringtone', style: TextStyle(color: Colors.white)),
subtitle: Text(_ringtone, style: const TextStyle(color: Colors.grey)),
trailing: const Icon(Icons.arrow_forward_ios, color: Colors.white),
onTap: () {
_selectRingtone(context);
},
),
],
),
);
}
void _selectRingtone(BuildContext context) {
showDialog<String>(
context: context,
builder: (BuildContext context) {
return SimpleDialog(
title: const Text('Select Ringtone'),
children: <Widget>[
SimpleDialogOption(
onPressed: () {
Navigator.pop(context, 'Default');
},
child: const Text('Default'),
),
SimpleDialogOption(
onPressed: () {
Navigator.pop(context, 'Classic');
},
child: const Text('Classic'),
),
SimpleDialogOption(
onPressed: () {
Navigator.pop(context, 'Beep');
},
child: const Text('Beep'),
),
// Add more ringtone options
],
);
},
).then((value) {
if (value != null) {
setState(() {
_ringtone = value;
});
}
});
}
}

View File

@ -0,0 +1,68 @@
// delete_key_pair.dart
import 'package:flutter/material.dart';
class SuppressionPaireClesPage extends StatelessWidget {
const SuppressionPaireClesPage({super.key});
void _deleteKeyPair(BuildContext context) {
// key deletion logic (not implemented here)
// ...
// Show confirmation message
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('La paire de clés a été supprimée.'),
),
);
// Navigate back or update the UI as needed
Navigator.pop(context);
}
void _showConfirmationDialog(BuildContext context) {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: const Text('Confirmer la Suppression'),
content: const Text(
'Êtes-vous sûr de vouloir supprimer la paire de clés ? Cette action est irréversible.'),
actions: [
TextButton(
child: const Text('Annuler'),
onPressed: () {
Navigator.of(context).pop();
},
),
TextButton(
child: const Text('Supprimer'),
onPressed: () {
Navigator.of(context).pop();
_deleteKeyPair(context);
},
),
],
);
},
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.black,
appBar: AppBar(
title: const Text('Suppression d\'une Paire de Clés'),
),
body: Center(
child: ElevatedButton(
onPressed: () {
_showConfirmationDialog(context);
},
child: const Text('Supprimer la Paire de Clés'),
),
),
);
}
}

View File

@ -0,0 +1,112 @@
// export_private_key.dart
import 'package:flutter/material.dart';
import 'dart:typed_data';
import 'dart:convert';
import 'package:pointycastle/export.dart' as crypto;
import 'package:file_picker/file_picker.dart';
class ExportationClePriveePage extends StatefulWidget {
const ExportationClePriveePage({super.key});
@override
_ExportationClePriveePageState createState() => _ExportationClePriveePageState();
}
class _ExportationClePriveePageState extends State<ExportationClePriveePage> {
final TextEditingController _passwordController = TextEditingController();
Future<void> _exportPrivateKey() async {
// Replace with your actual private key retrieval logic
final String privateKeyPem = 'Votre clé privée ici';
// Get the password from the user input
final password = _passwordController.text;
if (password.isEmpty) {
// Show error message
return;
}
// Encrypt the private key using AES-256
final encryptedData = _encryptPrivateKey(privateKeyPem, password);
// Let the user pick a file location
final outputFile = await FilePicker.platform.saveFile(
dialogTitle: 'Enregistrer la clé privée chiffrée',
fileName: 'private_key_encrypted.aes',
);
if (outputFile != null) {
// Write the encrypted data to the file
// Use appropriate file I/O methods (not shown here)
// ...
// Show a confirmation dialog or message
showDialog(
context: context,
builder: (context) => AlertDialog(
title: const Text('Clé Exportée'),
content: const Text('La clé privée chiffrée a été exportée avec succès.'),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: const Text('OK'),
),
],
),
);
}
}
Uint8List _encryptPrivateKey(String privateKey, String password) {
// Encryption logic using AES-256
final key = crypto.PBKDF2KeyDerivator(crypto.HMac(crypto.SHA256Digest(), 64))
.process(Uint8List.fromList(utf8.encode(password)));
final params = crypto.PaddedBlockCipherParameters(
crypto.ParametersWithIV(crypto.KeyParameter(key), Uint8List(16)), // Initialization Vector
null,
);
final cipher = crypto.PaddedBlockCipher('AES/CBC/PKCS7');
cipher.init(true, params);
final input = Uint8List.fromList(utf8.encode(privateKey));
final output = cipher.process(input);
return output;
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.black,
appBar: AppBar(
title: const Text('Exportation de la Clé Privée'),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
const Text(
'Entrez un mot de passe pour chiffrer la clé privée:',
style: TextStyle(color: Colors.white),
),
TextField(
controller: _passwordController,
obscureText: true,
style: const TextStyle(color: Colors.white),
decoration: const InputDecoration(
hintText: 'Mot de passe',
hintStyle: TextStyle(color: Colors.grey),
),
),
const SizedBox(height: 20),
ElevatedButton(
onPressed: _exportPrivateKey,
child: const Text('Exporter la Clé Privée Chiffrée'),
),
],
),
),
);
}
}

View File

@ -0,0 +1,123 @@
import 'package:flutter/material.dart';
import 'package:pointycastle/export.dart' as crypto;
import 'dart:math';
import 'dart:convert';
import 'dart:typed_data';
import 'package:asn1lib/asn1lib.dart';
class GenerationNouvellePaireClesPage extends StatelessWidget {
const GenerationNouvellePaireClesPage({super.key});
Future<Map<String, String>> _generateKeyPair() async {
// key generation logic using pointycastle
final keyParams = crypto.RSAKeyGeneratorParameters(
BigInt.parse('65537'),
2048,
64,
);
final secureRandom = crypto.FortunaRandom();
// Seed the random number generator
final random = Random.secure();
final seeds = List<int>.generate(32, (_) => random.nextInt(256));
secureRandom.seed(crypto.KeyParameter(Uint8List.fromList(seeds)));
final rngParams = crypto.ParametersWithRandom(keyParams, secureRandom);
final keyGenerator = crypto.RSAKeyGenerator();
keyGenerator.init(rngParams);
final pair = keyGenerator.generateKeyPair();
final publicKey = pair.publicKey as crypto.RSAPublicKey;
final privateKey = pair.privateKey as crypto.RSAPrivateKey;
// Convert keys to PEM format
final publicKeyPem = _encodePublicKeyToPemPKCS1(publicKey);
final privateKeyPem = _encodePrivateKeyToPemPKCS1(privateKey);
// Save keys securely (not implemented here)
return {'publicKey': publicKeyPem, 'privateKey': privateKeyPem};
}
String _encodePublicKeyToPemPKCS1(crypto.RSAPublicKey publicKey) {
final bytes = _encodePublicKeyToDer(publicKey);
return _formatPem(bytes, 'RSA PUBLIC KEY');
}
String _encodePrivateKeyToPemPKCS1(crypto.RSAPrivateKey privateKey) {
final bytes = _encodePrivateKeyToDer(privateKey);
return _formatPem(bytes, 'RSA PRIVATE KEY');
}
Uint8List _encodePublicKeyToDer(crypto.RSAPublicKey publicKey) {
final algorithmSeq = ASN1Sequence();
algorithmSeq.add(ASN1ObjectIdentifier.fromName('rsaEncryption'));
algorithmSeq.add(ASN1Null());
final publicKeySeq = ASN1Sequence();
publicKeySeq.add(ASN1Integer(publicKey.modulus!));
publicKeySeq.add(ASN1Integer(publicKey.exponent!));
final publicKeyBitString = ASN1BitString(Uint8List.fromList(publicKeySeq.encodedBytes));
final topLevelSeq = ASN1Sequence();
topLevelSeq.add(algorithmSeq);
topLevelSeq.add(publicKeyBitString);
return Uint8List.fromList(topLevelSeq.encodedBytes);
}
Uint8List _encodePrivateKeyToDer(crypto.RSAPrivateKey privateKey) {
final privateKeySeq = ASN1Sequence();
privateKeySeq.add(ASN1Integer(BigInt.from(0))); // Version
privateKeySeq.add(ASN1Integer(privateKey.n!));
privateKeySeq.add(ASN1Integer(privateKey.exponent!));
privateKeySeq.add(ASN1Integer(privateKey.d!));
privateKeySeq.add(ASN1Integer(privateKey.p!));
privateKeySeq.add(ASN1Integer(privateKey.q!));
privateKeySeq.add(ASN1Integer(privateKey.d! % (privateKey.p! - BigInt.one)));
privateKeySeq.add(ASN1Integer(privateKey.d! % (privateKey.q! - BigInt.one)));
privateKeySeq.add(ASN1Integer(privateKey.q!.modInverse(privateKey.p!)));
return Uint8List.fromList(privateKeySeq.encodedBytes);
}
String _formatPem(Uint8List bytes, String label) {
final base64 = base64Encode(bytes);
final chunks = RegExp('.{1,64}').allMatches(base64).map((m) => m.group(0)!);
return '-----BEGIN $label-----\n${chunks.join('\n')}\n-----END $label-----';
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.black,
appBar: AppBar(
title: const Text('Génération d\'une Nouvelle Paire de Clés'),
),
body: Center(
child: ElevatedButton(
onPressed: () async {
final keys = await _generateKeyPair();
// Display a confirmation dialog or message
showDialog(
context: context,
builder: (context) => AlertDialog(
title: const Text('Clés Générées'),
content: const Text('La nouvelle paire de clés a été générée avec succès.'),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: const Text('OK'),
),
],
),
);
},
child: const Text('Générer une Nouvelle Paire de Clés'),
),
),
);
}
}

View File

@ -0,0 +1,83 @@
// manage_keys_page.dart
import 'package:flutter/material.dart';
import 'package:dialer/features/settings/key/show_public_key_text.dart';
import 'package:dialer/features/settings/key/show_public_key_qr.dart';
import 'package:dialer/features/settings/key/generate_new_key_pair.dart';
import 'package:dialer/features/settings/key/export_private_key.dart';
import 'package:dialer/features/settings/key/delete_key_pair.dart';
class GestionDeClesPage extends StatelessWidget {
const GestionDeClesPage({super.key});
void _navigateToOption(BuildContext context, String option) {
switch (option) {
case 'Affichage de la clé publique en texte':
Navigator.push(
context,
MaterialPageRoute(builder: (context) => const AffichageClePubliqueTextePage()),
);
break;
case 'Affichage de la clé publique en QR code':
Navigator.push(
context,
MaterialPageRoute(builder: (context) => const AffichageClePubliqueQRCodePage()),
);
break;
case 'Génération d\'une nouvelle paire de clés':
Navigator.push(
context,
MaterialPageRoute(builder: (context) => const GenerationNouvellePaireClesPage()),
);
break;
case 'Exportation de la clé privée en fichier chiffré par mot de passe (AES 256)':
Navigator.push(
context,
MaterialPageRoute(builder: (context) => const ExportationClePriveePage()),
);
break;
case 'Suppression d\'une paire de clés, POPUP d\'avertissement':
Navigator.push(
context,
MaterialPageRoute(builder: (context) => const SuppressionPaireClesPage()),
);
break;
default:
// Handle default or unknown options
break;
}
}
@override
Widget build(BuildContext context) {
final keyManagementOptions = [
'Affichage de la clé publique en texte',
'Affichage de la clé publique en QR code',
'Génération d\'une nouvelle paire de clés',
'Exportation de la clé privée en fichier chiffré par mot de passe (AES 256)',
'Suppression d\'une paire de clés, POPUP d\'avertissement',
];
return Scaffold(
backgroundColor: Colors.black,
appBar: AppBar(
title: const Text('Gestion de clés'),
),
body: ListView.builder(
itemCount: keyManagementOptions.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(
keyManagementOptions[index],
style: const TextStyle(color: Colors.white),
),
trailing: const Icon(Icons.arrow_forward_ios, color: Colors.white),
onTap: () {
_navigateToOption(context, keyManagementOptions[index]);
},
);
},
),
);
}
}

View File

@ -0,0 +1,27 @@
import 'package:flutter/material.dart';
import 'package:pretty_qr_code/pretty_qr_code.dart';
class AffichageClePubliqueQRCodePage extends StatelessWidget {
const AffichageClePubliqueQRCodePage({super.key});
@override
Widget build(BuildContext context) {
// Replace with your actual public key retrieval logic
final String publicKey = 'Votre clé publique ici';
return Scaffold(
backgroundColor: Colors.black,
appBar: AppBar(
title: const Text('Clé Publique en QR Code'),
),
body: Center(
child: PrettyQr(
data: publicKey,
size: 250,
roundEdges: true,
elementColor: Colors.white,
),
),
);
}
}

View File

@ -0,0 +1,30 @@
// show_public_key_text.dart
import 'package:flutter/material.dart';
class AffichageClePubliqueTextePage extends StatelessWidget {
const AffichageClePubliqueTextePage({super.key});
@override
Widget build(BuildContext context) {
// Replace with your actual public key retrieval logic
final String publicKey = 'Votre clé publique ici';
return Scaffold(
backgroundColor: Colors.black,
appBar: AppBar(
title: const Text('Clé Publique en Texte'),
),
body: Center(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: SelectableText(
publicKey,
style: const TextStyle(color: Colors.white),
textAlign: TextAlign.center,
),
),
),
);
}
}

View File

@ -0,0 +1,68 @@
// settings.dart
import 'package:flutter/material.dart';
import 'package:dialer/features/settings/call/settingsCall.dart';
import 'package:dialer/features/settings/sim/settings_accounts.dart';
import 'package:dialer/features/settings/key/manage_keys_page.dart';
class SettingsPage extends StatelessWidget {
const SettingsPage({super.key});
void _navigateToSettings(BuildContext context, String setting) {
switch (setting) {
case 'Calling settings':
Navigator.push(
context,
MaterialPageRoute(builder: (context) => const SettingsCallPage()),
);
break;
case 'Page des comptes téléphoniques':
Navigator.push(
context,
MaterialPageRoute(builder: (context) => const SettingsAccountsPage()),
);
break;
case 'Gestion de clés':
Navigator.push(
context,
MaterialPageRoute(builder: (context) => const GestionDeClesPage()),
);
break;
// Add more cases for other settings pages
default:
// Handle default or unknown settings
break;
}
}
@override
Widget build(BuildContext context) {
final settingsOptions = [
'Calling settings',
'Page des comptes téléphoniques',
'Gestion de clés', // Add the new option here
];
return Scaffold(
backgroundColor: Colors.black,
appBar: AppBar(
title: const Text('settings'),
),
body: ListView.builder(
itemCount: settingsOptions.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(
settingsOptions[index],
style: const TextStyle(color: Colors.white),
),
trailing: const Icon(Icons.arrow_forward_ios, color: Colors.white),
onTap: () {
_navigateToSettings(context, settingsOptions[index]);
},
);
},
),
);
}
}

View File

@ -0,0 +1,87 @@
// choose_sim.dart
import 'package:flutter/material.dart';
import 'package:sim_data/sim_data.dart';
import 'package:permission_handler/permission_handler.dart';
class ChooseSimPage extends StatefulWidget {
const ChooseSimPage({super.key});
@override
_ChooseSimPageState createState() => _ChooseSimPageState();
}
class _ChooseSimPageState extends State<ChooseSimPage> {
List<SimCard> _simCards = [];
int? _selectedSimIndex;
@override
void initState() {
super.initState();
_fetchSimCards();
}
Future<void> _fetchSimCards() async {
if (await Permission.phone.request().isGranted) {
try {
final simData = await SimDataPlugin.getSimData();
setState(() {
_simCards = simData.cards;
_selectedSimIndex = 0;
});
} catch (e) {
// Handle error
print('Error fetching SIM data: $e');
}
} else {
// Permission denied
print('Phone permission denied');
}
}
void _onSimSelected(int? index) {
if (index != null) {
setState(() {
_selectedSimIndex = index;
});
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.black,
appBar: AppBar(
title: const Text('Choisir la SIM'),
),
body: _simCards.isEmpty
? const Center(
child: Text(
'Aucune carte SIM trouvée',
style: TextStyle(color: Colors.white),
),
)
: ListView.builder(
itemCount: _simCards.length,
itemBuilder: (context, index) {
final sim = _simCards[index];
return ListTile(
title: Text(
'SIM ${index + 1}',
style: const TextStyle(color: Colors.white),
),
subtitle: Text(
'Opérateur: ${sim.carrierName}',
style: const TextStyle(color: Colors.grey),
),
trailing: Radio<int>(
value: index,
groupValue: _selectedSimIndex,
onChanged: _onSimSelected,
),
);
},
),
);
}
}

View File

@ -0,0 +1,59 @@
// settings_accounts.dart
import 'package:flutter/material.dart';
import 'package:dialer/features/settings/sim/choose_sim.dart';
import 'package:dialer/features/settings/sim/sim_parameters.dart';
class SettingsAccountsPage extends StatelessWidget {
const SettingsAccountsPage({super.key});
void _navigateToAccountOption(BuildContext context, String option) {
switch (option) {
case 'Choisir la SIM':
Navigator.push(
context,
MaterialPageRoute(builder: (context) => const ChooseSimPage()),
);
break;
case 'Paramètre SIM':
Navigator.push(
context,
MaterialPageRoute(builder: (context) => const SimParametersPage()),
);
break;
// Handle more options if needed
default:
break;
}
}
@override
Widget build(BuildContext context) {
final accountOptions = [
'Choisir la SIM',
'Paramètre SIM',
];
return Scaffold(
backgroundColor: Colors.black,
appBar: AppBar(
title: const Text('Page des comptes téléphoniques'),
),
body: ListView.builder(
itemCount: accountOptions.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(
accountOptions[index],
style: const TextStyle(color: Colors.white),
),
trailing: const Icon(Icons.arrow_forward_ios, color: Colors.white),
onTap: () {
_navigateToAccountOption(context, accountOptions[index]);
},
);
},
),
);
}
}

View File

@ -0,0 +1,85 @@
// sim_parameters.dart
import 'package:flutter/material.dart';
import 'package:sim_data/sim_data.dart';
import 'package:permission_handler/permission_handler.dart';
class SimParametersPage extends StatefulWidget {
const SimParametersPage({super.key});
@override
_SimParametersPageState createState() => _SimParametersPageState();
}
class _SimParametersPageState extends State<SimParametersPage> {
List<SimCard> _simCards = [];
@override
void initState() {
super.initState();
_fetchSimParameters();
}
Future<void> _fetchSimParameters() async {
if (await Permission.phone.request().isGranted) {
try {
final simData = await SimDataPlugin.getSimData();
setState(() {
_simCards = simData.cards;
});
} catch (e) {
// Handle error
print('Error fetching SIM data: $e');
}
} else {
// Permission denied
print('Phone permission denied');
}
}
Widget _buildSimInfo(SimCard sim, int index) {
return Card(
color: Colors.grey[850],
child: ListTile(
title: Text(
'SIM ${index + 1}',
style: const TextStyle(color: Colors.white),
),
subtitle: Text(
'''
Opérateur: ${sim.carrierName}
Pays: ${sim.countryCode ?? 'N/A'}
MCC: ${sim.mcc ?? 'N/A'}
MNC: ${sim.mnc ?? 'N/A'}
Slot Index: ${sim.slotIndex ?? 'N/A'}
Display Name: ${sim.displayName ?? 'N/A'}
''',
style: const TextStyle(color: Colors.grey),
),
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.black,
appBar: AppBar(
title: const Text('Paramètre SIM'),
),
body: _simCards.isEmpty
? const Center(
child: Text(
'Aucune carte SIM trouvée',
style: TextStyle(color: Colors.white),
),
)
: ListView.builder(
itemCount: _simCards.length,
itemBuilder: (context, index) {
return _buildSimInfo(_simCards[index], index);
},
),
);
}
}

View File

@ -38,6 +38,12 @@ dependencies:
flutter_contacts: ^1.1.9+2
permission_handler: ^10.2.0 # For handling permissions
cached_network_image: ^3.2.3 # For caching contact images
sim_data: ^0.0.2
pretty_qr_code: ^3.3.0
pointycastle: ^3.4.0
file_picker: ^5.2.5
asn1lib: ^1.0.0
intl_utils: ^2.0.7
dev_dependencies:
flutter_test: