Compare commits
3 Commits
dev
...
about-page
Author | SHA1 | Date | |
---|---|---|---|
|
a418844534 | ||
|
051ce4680a | ||
|
0023f1a7c5 |
322
dialer/lib/features/about/about.dart
Normal file
322
dialer/lib/features/about/about.dart
Normal file
@ -0,0 +1,322 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:package_info_plus/package_info_plus.dart';
|
||||||
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
|
|
||||||
|
class AboutPage extends StatefulWidget {
|
||||||
|
const AboutPage({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
_AboutPageState createState() => _AboutPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _AboutPageState extends State<AboutPage> {
|
||||||
|
String _version = '';
|
||||||
|
String _buildNumber = '';
|
||||||
|
bool _isLoading = true;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_loadPackageInfo();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _loadPackageInfo() async {
|
||||||
|
final packageInfo = await PackageInfo.fromPlatform();
|
||||||
|
setState(() {
|
||||||
|
_version = packageInfo.version;
|
||||||
|
_buildNumber = packageInfo.buildNumber;
|
||||||
|
_isLoading = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _launchURL(String url) async {
|
||||||
|
final uri = Uri.parse(url);
|
||||||
|
if (await canLaunchUrl(uri)) {
|
||||||
|
await launchUrl(uri, mode: LaunchMode.externalApplication);
|
||||||
|
} else {
|
||||||
|
throw 'Could not launch $url';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
backgroundColor: Colors.black,
|
||||||
|
appBar: AppBar(
|
||||||
|
title: const Text('About'),
|
||||||
|
backgroundColor: Colors.black,
|
||||||
|
elevation: 0,
|
||||||
|
),
|
||||||
|
body: _isLoading
|
||||||
|
? const Center(child: CircularProgressIndicator())
|
||||||
|
: SingleChildScrollView(
|
||||||
|
padding: const EdgeInsets.all(20.0),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
// App Logo and Name
|
||||||
|
Center(
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
width: 100,
|
||||||
|
height: 100,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.blue,
|
||||||
|
borderRadius: BorderRadius.circular(20),
|
||||||
|
),
|
||||||
|
child: const Icon(
|
||||||
|
Icons.phone,
|
||||||
|
size: 60,
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
const Text(
|
||||||
|
'Icing Dialer',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 24,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
'Version $_version (Build $_buildNumber)',
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.grey[400],
|
||||||
|
fontSize: 14,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 32),
|
||||||
|
// App Description
|
||||||
|
const _SectionHeader(title: 'About This App'),
|
||||||
|
const _ContentCard(
|
||||||
|
child: Text(
|
||||||
|
'Icing Dialer is a secure and privacy-focused phone dialer application '
|
||||||
|
'designed to provide a modern, user-friendly interface for making calls, '
|
||||||
|
'managing contacts, and accessing your call history. With features like '
|
||||||
|
'contact obfuscation and encryption protocols, your communication remains '
|
||||||
|
'private and secure.',
|
||||||
|
style: TextStyle(color: Colors.white, height: 1.5),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 24),
|
||||||
|
// Features
|
||||||
|
const _SectionHeader(title: 'Key Features'),
|
||||||
|
const _ContentCard(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
_FeatureItem(
|
||||||
|
icon: Icons.phone,
|
||||||
|
title: 'Intuitive Calling Interface',
|
||||||
|
description: 'Easy-to-use dialer with quick access to frequent contacts.',
|
||||||
|
),
|
||||||
|
SizedBox(height: 16),
|
||||||
|
_FeatureItem(
|
||||||
|
icon: Icons.lock,
|
||||||
|
title: 'Secure Communications',
|
||||||
|
description: 'End-to-end encrypted calls with the Icing protocol.',
|
||||||
|
),
|
||||||
|
SizedBox(height: 16),
|
||||||
|
_FeatureItem(
|
||||||
|
icon: Icons.history,
|
||||||
|
title: 'Comprehensive Call History',
|
||||||
|
description: 'View, filter, and manage your recent calls.',
|
||||||
|
),
|
||||||
|
SizedBox(height: 16),
|
||||||
|
_FeatureItem(
|
||||||
|
icon: Icons.contacts,
|
||||||
|
title: 'Advanced Contact Management',
|
||||||
|
description: 'Organize, share, and secure your contacts.',
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 24),
|
||||||
|
// Support & Privacy
|
||||||
|
const _SectionHeader(title: 'Support & Privacy'),
|
||||||
|
_ContentCard(
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
_LinkButton(
|
||||||
|
icon: Icons.help_outline,
|
||||||
|
text: 'Help & Support',
|
||||||
|
onTap: () => _launchURL('https://icing.org/support'),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 12),
|
||||||
|
_LinkButton(
|
||||||
|
icon: Icons.privacy_tip_outlined,
|
||||||
|
text: 'Privacy Policy',
|
||||||
|
onTap: () => _launchURL('https://icing.org/privacy'),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 12),
|
||||||
|
_LinkButton(
|
||||||
|
icon: Icons.description_outlined,
|
||||||
|
text: 'Terms of Service',
|
||||||
|
onTap: () => _launchURL('https://icing.org/terms'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 24),
|
||||||
|
// Credits
|
||||||
|
const _SectionHeader(title: 'Credits'),
|
||||||
|
const _ContentCard(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'Developed by Icing Team',
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.white,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(height: 8),
|
||||||
|
Text(
|
||||||
|
'This application utilizes open-source libraries and follows best '
|
||||||
|
'practices for secure software development.',
|
||||||
|
style: TextStyle(color: Colors.white70, height: 1.5),
|
||||||
|
),
|
||||||
|
SizedBox(height: 12),
|
||||||
|
Text(
|
||||||
|
'© 2025 Icing Organization. All Rights Reserved.',
|
||||||
|
style: TextStyle(color: Colors.grey, fontSize: 12),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 40),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _SectionHeader extends StatelessWidget {
|
||||||
|
final String title;
|
||||||
|
|
||||||
|
const _SectionHeader({Key? key, required this.title}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.only(bottom: 8.0),
|
||||||
|
child: Text(
|
||||||
|
title,
|
||||||
|
style: const TextStyle(
|
||||||
|
color: Colors.blue,
|
||||||
|
fontSize: 18,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ContentCard extends StatelessWidget {
|
||||||
|
final Widget child;
|
||||||
|
|
||||||
|
const _ContentCard({Key? key, required this.child}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
width: double.infinity,
|
||||||
|
padding: const EdgeInsets.all(16),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.grey[900],
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
),
|
||||||
|
child: child,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _FeatureItem extends StatelessWidget {
|
||||||
|
final IconData icon;
|
||||||
|
final String title;
|
||||||
|
final String description;
|
||||||
|
|
||||||
|
const _FeatureItem({
|
||||||
|
Key? key,
|
||||||
|
required this.icon,
|
||||||
|
required this.title,
|
||||||
|
required this.description,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Icon(icon, color: Colors.blue, size: 20),
|
||||||
|
const SizedBox(width: 12),
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
title,
|
||||||
|
style: const TextStyle(
|
||||||
|
color: Colors.white,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 4),
|
||||||
|
Text(
|
||||||
|
description,
|
||||||
|
style: const TextStyle(color: Colors.white70),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _LinkButton extends StatelessWidget {
|
||||||
|
final IconData icon;
|
||||||
|
final String text;
|
||||||
|
final VoidCallback onTap;
|
||||||
|
|
||||||
|
const _LinkButton({
|
||||||
|
Key? key,
|
||||||
|
required this.icon,
|
||||||
|
required this.text,
|
||||||
|
required this.onTap,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return InkWell(
|
||||||
|
onTap: onTap,
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 8.0),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Icon(icon, color: Colors.blue),
|
||||||
|
const SizedBox(width: 16),
|
||||||
|
Text(
|
||||||
|
text,
|
||||||
|
style: const TextStyle(color: Colors.white),
|
||||||
|
),
|
||||||
|
const Spacer(),
|
||||||
|
const Icon(
|
||||||
|
Icons.arrow_forward_ios,
|
||||||
|
color: Colors.white70,
|
||||||
|
size: 16,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -9,6 +9,7 @@ import 'package:dialer/features/settings/settings.dart';
|
|||||||
import '../../services/contact_service.dart';
|
import '../../services/contact_service.dart';
|
||||||
import 'package:dialer/features/voicemail/voicemail_page.dart';
|
import 'package:dialer/features/voicemail/voicemail_page.dart';
|
||||||
import '../contacts/widgets/contact_modal.dart';
|
import '../contacts/widgets/contact_modal.dart';
|
||||||
|
import 'package:dialer/features/about/about.dart'; // Add this import
|
||||||
|
|
||||||
|
|
||||||
class _MyHomePageState extends State<MyHomePage>
|
class _MyHomePageState extends State<MyHomePage>
|
||||||
@ -233,6 +234,10 @@ class _MyHomePageState extends State<MyHomePage>
|
|||||||
value: 'settings',
|
value: 'settings',
|
||||||
child: Text('Settings'),
|
child: Text('Settings'),
|
||||||
),
|
),
|
||||||
|
const PopupMenuItem<String>( // Add About menu item
|
||||||
|
value: 'about',
|
||||||
|
child: Text('About'),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
onSelected: (String value) {
|
onSelected: (String value) {
|
||||||
if (value == 'settings') {
|
if (value == 'settings') {
|
||||||
@ -241,6 +246,12 @@ class _MyHomePageState extends State<MyHomePage>
|
|||||||
MaterialPageRoute(
|
MaterialPageRoute(
|
||||||
builder: (context) => const SettingsPage()),
|
builder: (context) => const SettingsPage()),
|
||||||
);
|
);
|
||||||
|
} else if (value == 'about') { // Handle About selection
|
||||||
|
Navigator.push(
|
||||||
|
context,
|
||||||
|
MaterialPageRoute(
|
||||||
|
builder: (context) => const AboutPage()),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
@ -55,6 +55,7 @@ dependencies:
|
|||||||
encrypt: ^5.0.3
|
encrypt: ^5.0.3
|
||||||
uuid: ^4.5.1
|
uuid: ^4.5.1
|
||||||
provider: ^6.1.2
|
provider: ^6.1.2
|
||||||
|
package_info_plus: ^8.3.0
|
||||||
|
|
||||||
intl: any
|
intl: any
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user