From 0023f1a7c53370964c09ffd5f6e89b8a5e63c7cf Mon Sep 17 00:00:00 2001 From: AlexisDanlos <91090088+AlexisDanlos@users.noreply.github.com> Date: Sat, 22 Mar 2025 23:10:48 +0100 Subject: [PATCH] Added about page --- dialer/lib/features/about/about.dart | 331 ++++++++++++++++++++++++ dialer/lib/features/home/home_page.dart | 11 + dialer/pubspec.yaml | 1 + 3 files changed, 343 insertions(+) create mode 100644 dialer/lib/features/about/about.dart diff --git a/dialer/lib/features/about/about.dart b/dialer/lib/features/about/about.dart new file mode 100644 index 0000000..0ba21ab --- /dev/null +++ b/dialer/lib/features/about/about.dart @@ -0,0 +1,331 @@ +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 { + String _version = ''; + String _buildNumber = ''; + bool _isLoading = true; + + @override + void initState() { + super.initState(); + _loadPackageInfo(); + } + + Future _loadPackageInfo() async { + final packageInfo = await PackageInfo.fromPlatform(); + setState(() { + _version = packageInfo.version; + _buildNumber = packageInfo.buildNumber; + _isLoading = false; + }); + } + + Future _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( + '© 2023 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, + ), + ], + ), + ), + ); + } +} diff --git a/dialer/lib/features/home/home_page.dart b/dialer/lib/features/home/home_page.dart index 65adaa8..e3816ef 100644 --- a/dialer/lib/features/home/home_page.dart +++ b/dialer/lib/features/home/home_page.dart @@ -9,6 +9,7 @@ import 'package:dialer/features/settings/settings.dart'; import '../../services/contact_service.dart'; import 'package:dialer/features/voicemail/voicemail_page.dart'; import '../contacts/widgets/contact_modal.dart'; +import 'package:dialer/features/about/about.dart'; // Add this import class _MyHomePageState extends State @@ -233,6 +234,10 @@ class _MyHomePageState extends State value: 'settings', child: Text('Settings'), ), + const PopupMenuItem( // Add About menu item + value: 'about', + child: Text('About'), + ), ], onSelected: (String value) { if (value == 'settings') { @@ -241,6 +246,12 @@ class _MyHomePageState extends State MaterialPageRoute( builder: (context) => const SettingsPage()), ); + } else if (value == 'about') { // Handle About selection + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => const AboutPage()), + ); } }, ), diff --git a/dialer/pubspec.yaml b/dialer/pubspec.yaml index 244050a..5be9252 100644 --- a/dialer/pubspec.yaml +++ b/dialer/pubspec.yaml @@ -55,6 +55,7 @@ dependencies: encrypt: ^5.0.3 uuid: ^4.5.1 provider: ^6.1.2 + package_info_plus: ^8.3.0 intl: any