From 6fbd4b426e891861cc08ec9fc9b8d9942a2b2584 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20M=C3=BCllner?= Date: Tue, 24 Feb 2026 16:22:26 +0100 Subject: [PATCH] fix: update package namespace and identifiers to com.derkauzigekoala.hwhub; add About screen with app info and links --- android/app/build.gradle.kts | 4 +- .../hwhub/MainActivity.kt | 2 +- ios/Runner.xcodeproj/project.pbxproj | 12 +- lib/screens/about_screen.dart | 244 ++++++++++++++++++ lib/screens/profile_screen.dart | 23 +- linux/CMakeLists.txt | 2 +- macos/Flutter/GeneratedPluginRegistrant.swift | 2 + macos/Runner.xcodeproj/project.pbxproj | 6 +- macos/Runner/Configs/AppInfo.xcconfig | 2 +- pubspec.lock | 26 +- pubspec.yaml | 2 + 11 files changed, 290 insertions(+), 35 deletions(-) rename android/app/src/main/kotlin/com/{example => derkauzigekoala}/hwhub/MainActivity.kt (73%) create mode 100644 lib/screens/about_screen.dart diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts index 7bb6aed..8377968 100644 --- a/android/app/build.gradle.kts +++ b/android/app/build.gradle.kts @@ -6,7 +6,7 @@ plugins { } android { - namespace = "com.example.hwhub" + namespace = "com.derkauzigekoala.hwhub" compileSdk = flutter.compileSdkVersion ndkVersion = flutter.ndkVersion @@ -21,7 +21,7 @@ android { defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). - applicationId = "com.example.hwhub" + applicationId = "com.derkauzigekoala.hwhub" // You can update the following values to match your application needs. // For more information, see: https://flutter.dev/to/review-gradle-config. minSdk = flutter.minSdkVersion diff --git a/android/app/src/main/kotlin/com/example/hwhub/MainActivity.kt b/android/app/src/main/kotlin/com/derkauzigekoala/hwhub/MainActivity.kt similarity index 73% rename from android/app/src/main/kotlin/com/example/hwhub/MainActivity.kt rename to android/app/src/main/kotlin/com/derkauzigekoala/hwhub/MainActivity.kt index 5920591..b6bc733 100644 --- a/android/app/src/main/kotlin/com/example/hwhub/MainActivity.kt +++ b/android/app/src/main/kotlin/com/derkauzigekoala/hwhub/MainActivity.kt @@ -1,4 +1,4 @@ -package com.example.hwhub +package com.derkauzigekoala.hwhub import io.flutter.embedding.android.FlutterActivity diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 9621777..94423af 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -372,7 +372,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.hwhub; + PRODUCT_BUNDLE_IDENTIFIER = com.derkauzigekoala.hwhub; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; @@ -388,7 +388,7 @@ CURRENT_PROJECT_VERSION = 1; GENERATE_INFOPLIST_FILE = YES; MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.example.hwhub.RunnerTests; + PRODUCT_BUNDLE_IDENTIFIER = com.derkauzigekoala.hwhub.RunnerTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; @@ -405,7 +405,7 @@ CURRENT_PROJECT_VERSION = 1; GENERATE_INFOPLIST_FILE = YES; MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.example.hwhub.RunnerTests; + PRODUCT_BUNDLE_IDENTIFIER = com.derkauzigekoala.hwhub.RunnerTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; @@ -420,7 +420,7 @@ CURRENT_PROJECT_VERSION = 1; GENERATE_INFOPLIST_FILE = YES; MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.example.hwhub.RunnerTests; + PRODUCT_BUNDLE_IDENTIFIER = com.derkauzigekoala.hwhub.RunnerTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; @@ -551,7 +551,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.hwhub; + PRODUCT_BUNDLE_IDENTIFIER = com.derkauzigekoala.hwhub; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; @@ -573,7 +573,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.hwhub; + PRODUCT_BUNDLE_IDENTIFIER = com.derkauzigekoala.hwhub; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; diff --git a/lib/screens/about_screen.dart b/lib/screens/about_screen.dart new file mode 100644 index 0000000..75726b1 --- /dev/null +++ b/lib/screens/about_screen.dart @@ -0,0 +1,244 @@ +import 'package:flutter/material.dart'; +import 'package:package_info_plus/package_info_plus.dart'; +import 'package:url_launcher/url_launcher.dart'; +import '../theme/app_colors.dart'; + +/// Full-page About screen with app info, version, and links. +class AboutScreen extends StatefulWidget { + const AboutScreen({super.key}); + + @override + State createState() => _AboutScreenState(); +} + +class _AboutScreenState extends State { + PackageInfo? _packageInfo; + + @override + void initState() { + super.initState(); + _loadPackageInfo(); + } + + Future _loadPackageInfo() async { + final info = await PackageInfo.fromPlatform(); + if (mounted) setState(() => _packageInfo = info); + } + + Future _openUrl(String url) async { + final uri = Uri.parse(url); + await launchUrl(uri, mode: LaunchMode.externalApplication); + } + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + final isDark = theme.brightness == Brightness.dark; + final version = _packageInfo != null + ? 'v${_packageInfo!.version} (${_packageInfo!.buildNumber})' + : '…'; + + return Scaffold( + appBar: AppBar( + title: const Text('About'), + ), + body: ListView( + padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16), + children: [ + const SizedBox(height: 16), + + // ── App icon + name ── + Center( + child: Container( + width: 96, + height: 96, + decoration: const BoxDecoration( + gradient: AppColors.brandGradient, + shape: BoxShape.circle, + ), + child: const Icon( + Icons.directions_car_filled, + color: Colors.white, + size: 52, + ), + ), + ), + const SizedBox(height: 16), + Center( + child: Text( + 'HW Collector Hub', + style: theme.textTheme.headlineSmall?.copyWith( + fontWeight: FontWeight.bold, + ), + ), + ), + const SizedBox(height: 4), + Center( + child: Text( + version, + style: theme.textTheme.bodyMedium?.copyWith( + color: AppColors.textSecondary, + ), + ), + ), + const SizedBox(height: 8), + Center( + child: Text( + 'Track and manage your Hot Wheels collection.', + style: theme.textTheme.bodyMedium?.copyWith( + color: AppColors.textHint, + ), + textAlign: TextAlign.center, + ), + ), + + const SizedBox(height: 32), + const Divider(), + const SizedBox(height: 16), + + // ── Links section ── + Text( + 'Links', + style: theme.textTheme.titleMedium?.copyWith( + fontWeight: FontWeight.w600, + color: AppColors.textSecondary, + ), + ), + const SizedBox(height: 8), + + _LinkTile( + icon: Icons.coffee, + iconColor: const Color(0xFFFFDD00), + title: 'Buy Me a Coffee', + subtitle: 'Support the development', + onTap: () => + _openUrl('https://buymeacoffee.com/derkauzigekoala'), + ), + + const SizedBox(height: 32), + const Divider(), + const SizedBox(height: 16), + + // ── Technical details ── + Text( + 'Technical', + style: theme.textTheme.titleMedium?.copyWith( + fontWeight: FontWeight.w600, + color: AppColors.textSecondary, + ), + ), + const SizedBox(height: 8), + + _InfoRow(label: 'Version', value: _packageInfo?.version ?? '…'), + _InfoRow( + label: 'Build', + value: _packageInfo?.buildNumber ?? '…', + ), + _InfoRow( + label: 'Package', + value: _packageInfo?.packageName ?? '…', + ), + + const SizedBox(height: 32), + + // ── Powered by ── + Center( + child: Column( + children: [ + Text( + 'Powered by Flutter & Supabase', + style: theme.textTheme.bodySmall?.copyWith( + color: AppColors.textHint, + ), + ), + const SizedBox(height: 4), + Text( + '© 2026 HW Collector Hub', + style: theme.textTheme.bodySmall?.copyWith( + color: AppColors.textHint, + ), + ), + ], + ), + ), + const SizedBox(height: 24), + ], + ), + ); + } +} + +// ── Link tile ───────────────────────────────────────────────────────── + +class _LinkTile extends StatelessWidget { + final IconData icon; + final Color iconColor; + final String title; + final String subtitle; + final VoidCallback onTap; + + const _LinkTile({ + required this.icon, + required this.iconColor, + required this.title, + required this.subtitle, + required this.onTap, + }); + + @override + Widget build(BuildContext context) { + return Card( + margin: const EdgeInsets.symmetric(vertical: 4), + child: ListTile( + leading: Container( + padding: const EdgeInsets.all(8), + decoration: BoxDecoration( + color: iconColor.withValues(alpha: 0.15), + borderRadius: BorderRadius.circular(10), + ), + child: Icon(icon, color: iconColor, size: 22), + ), + title: Text( + title, + style: const TextStyle(fontWeight: FontWeight.w500), + ), + subtitle: Text(subtitle, style: const TextStyle(fontSize: 12)), + trailing: const Icon(Icons.open_in_new, color: AppColors.textHint, size: 18), + onTap: onTap, + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(14)), + ), + ); + } +} + +// ── Info row (label : value) ────────────────────────────────────────── + +class _InfoRow extends StatelessWidget { + final String label; + final String value; + + const _InfoRow({required this.label, required this.value}); + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.symmetric(vertical: 6), + child: Row( + children: [ + Text( + label, + style: const TextStyle( + color: AppColors.textSecondary, + fontWeight: FontWeight.w500, + ), + ), + const Spacer(), + Text( + value, + style: const TextStyle(color: AppColors.textHint), + ), + ], + ), + ); + } +} diff --git a/lib/screens/profile_screen.dart b/lib/screens/profile_screen.dart index 47a498d..4564472 100644 --- a/lib/screens/profile_screen.dart +++ b/lib/screens/profile_screen.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import '../main.dart'; import '../theme/app_colors.dart'; +import 'about_screen.dart'; /// Profile / settings tab. class ProfileScreen extends StatelessWidget { @@ -197,26 +198,8 @@ class ProfileScreen extends StatelessWidget { } void _showAbout(BuildContext context) { - showAboutDialog( - context: context, - applicationName: 'HW Collector Hub', - applicationVersion: '1.1.0', - applicationIcon: Container( - width: 48, - height: 48, - decoration: const BoxDecoration( - gradient: AppColors.brandGradient, - shape: BoxShape.circle, - ), - child: const Icon( - Icons.directions_car_filled, - color: Colors.white, - size: 28, - ), - ), - children: [ - const Text('Track and manage your Hot Wheels collection.'), - ], + Navigator.of(context).push( + MaterialPageRoute(builder: (_) => const AboutScreen()), ); } } diff --git a/linux/CMakeLists.txt b/linux/CMakeLists.txt index e216ca9..fbfbf4e 100644 --- a/linux/CMakeLists.txt +++ b/linux/CMakeLists.txt @@ -7,7 +7,7 @@ project(runner LANGUAGES CXX) set(BINARY_NAME "hwhub") # The unique GTK application identifier for this application. See: # https://wiki.gnome.org/HowDoI/ChooseApplicationID -set(APPLICATION_ID "com.example.hwhub") +set(APPLICATION_ID "com.derkauzigekoala.hwhub") # Explicitly opt in to modern CMake behaviors to avoid warnings with recent # versions of CMake. diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 979ffec..48b4cb7 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -7,6 +7,7 @@ import Foundation import app_links import file_selector_macos +import package_info_plus import shared_preferences_foundation import sqflite_darwin import url_launcher_macos @@ -14,6 +15,7 @@ import url_launcher_macos func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { AppLinksMacosPlugin.register(with: registry.registrar(forPlugin: "AppLinksMacosPlugin")) FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin")) + FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin")) UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) diff --git a/macos/Runner.xcodeproj/project.pbxproj b/macos/Runner.xcodeproj/project.pbxproj index 47d3390..0f8f2ed 100644 --- a/macos/Runner.xcodeproj/project.pbxproj +++ b/macos/Runner.xcodeproj/project.pbxproj @@ -385,7 +385,7 @@ CURRENT_PROJECT_VERSION = 1; GENERATE_INFOPLIST_FILE = YES; MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.example.hwhub.RunnerTests; + PRODUCT_BUNDLE_IDENTIFIER = com.derkauzigekoala.hwhub.RunnerTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/hwhub.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/hwhub"; @@ -399,7 +399,7 @@ CURRENT_PROJECT_VERSION = 1; GENERATE_INFOPLIST_FILE = YES; MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.example.hwhub.RunnerTests; + PRODUCT_BUNDLE_IDENTIFIER = com.derkauzigekoala.hwhub.RunnerTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/hwhub.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/hwhub"; @@ -413,7 +413,7 @@ CURRENT_PROJECT_VERSION = 1; GENERATE_INFOPLIST_FILE = YES; MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.example.hwhub.RunnerTests; + PRODUCT_BUNDLE_IDENTIFIER = com.derkauzigekoala.hwhub.RunnerTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/hwhub.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/hwhub"; diff --git a/macos/Runner/Configs/AppInfo.xcconfig b/macos/Runner/Configs/AppInfo.xcconfig index c482ac0..bf0dd59 100644 --- a/macos/Runner/Configs/AppInfo.xcconfig +++ b/macos/Runner/Configs/AppInfo.xcconfig @@ -8,7 +8,7 @@ PRODUCT_NAME = hwhub // The application's bundle identifier -PRODUCT_BUNDLE_IDENTIFIER = com.example.hwhub +PRODUCT_BUNDLE_IDENTIFIER = com.derkauzigekoala.hwhub // The copyright displayed in application information PRODUCT_COPYRIGHT = Copyright © 2026 com.example. All rights reserved. diff --git a/pubspec.lock b/pubspec.lock index a5c9a2d..5665c72 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -640,6 +640,22 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.0" + package_info_plus: + dependency: "direct main" + description: + name: package_info_plus + sha256: "16eee997588c60225bda0488b6dcfac69280a6b7a3cf02c741895dd370a02968" + url: "https://pub.dev" + source: hosted + version: "8.3.1" + package_info_plus_platform_interface: + dependency: transitive + description: + name: package_info_plus_platform_interface + sha256: "202a487f08836a592a6bd4f901ac69b3a8f146af552bbd14407b6b41e1c3f086" + url: "https://pub.dev" + source: hosted + version: "3.2.1" path: dependency: transitive description: @@ -1030,7 +1046,7 @@ packages: source: hosted version: "2.3.1" url_launcher: - dependency: transitive + dependency: "direct main" description: name: url_launcher sha256: f6a7e5c4835bb4e3026a04793a4199ca2d14c739ec378fdfe23fc8075d0439f8 @@ -1141,6 +1157,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.3" + win32: + dependency: transitive + description: + name: win32 + sha256: d7cb55e04cd34096cd3a79b3330245f54cb96a370a1c27adb3c84b917de8b08e + url: "https://pub.dev" + source: hosted + version: "5.15.0" xdg_directories: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index dedae5f..b1a7b69 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -44,6 +44,8 @@ dependencies: intl: ^0.20.2 cached_network_image: ^3.4.1 uuid: ^4.5.1 + url_launcher: ^6.3.1 + package_info_plus: ^8.1.3 dev_dependencies: flutter_test: