diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index a102c69..aa71ce3 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -30,4 +30,21 @@ android:name="flutterEmbedding" android:value="2" /> + + + + + + + + + + + + + + + + + diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index c2f47d2..1342eed 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -445,6 +445,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; @@ -464,6 +465,7 @@ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; @@ -474,6 +476,7 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -502,10 +505,13 @@ DEVELOPMENT_TEAM = W7HPZ53V6B; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = GoatAgent; + INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.utilities"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); + MARKETING_VERSION = 1.0.0; PRODUCT_BUNDLE_IDENTIFIER = studio.smartsheep.goatagent; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; @@ -568,6 +574,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; @@ -587,6 +594,7 @@ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; @@ -597,6 +605,7 @@ DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; @@ -623,6 +632,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; @@ -642,6 +652,7 @@ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; @@ -652,6 +663,7 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -682,10 +694,13 @@ DEVELOPMENT_TEAM = W7HPZ53V6B; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = GoatAgent; + INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.utilities"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); + MARKETING_VERSION = 1.0.0; PRODUCT_BUNDLE_IDENTIFIER = studio.smartsheep.goatagent; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; @@ -706,10 +721,13 @@ DEVELOPMENT_TEAM = W7HPZ53V6B; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = GoatAgent; + INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.utilities"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); + MARKETING_VERSION = 1.0.0; PRODUCT_BUNDLE_IDENTIFIER = studio.smartsheep.goatagent; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index 2b9c475..606c466 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -7,7 +7,7 @@ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleDisplayName - Goatagent + GoatAgent CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier @@ -28,6 +28,11 @@ UIApplicationSupportsIndirectInputEvents + LSApplicationQueriesSchemes + + sms + tel + UIBackgroundModes fetch diff --git a/ios/Runner/Runner.entitlements b/ios/Runner/Runner.entitlements index 903def2..0c67376 100644 --- a/ios/Runner/Runner.entitlements +++ b/ios/Runner/Runner.entitlements @@ -1,8 +1,5 @@ - - aps-environment - development - + diff --git a/lib/main.dart b/lib/main.dart index 2eb5e95..265dc14 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:goatagent/auth.dart'; import 'package:goatagent/firebase.dart'; +import 'package:goatagent/screens/about.dart'; import 'package:goatagent/screens/account.dart'; import 'package:goatagent/screens/dashboard.dart'; import 'package:goatagent/screens/notifications.dart'; @@ -11,7 +12,13 @@ import 'layouts/navigation.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); - AuthGuard().pickClient(); + try { + await initializeFirebase(); + } catch (e) { + print(e); + } + + await AuthGuard().pickClient(); runApp(GoatAgent()); } @@ -32,6 +39,10 @@ class GoatAgent extends StatelessWidget { path: '/account', builder: (context, state) => const AccountScreen(), ), + GoRoute( + path: '/about', + builder: (context, state) => const AboutScreen(), + ), ], ); @@ -39,34 +50,23 @@ class GoatAgent extends StatelessWidget { @override Widget build(BuildContext context) { - return FutureBuilder( - future: initializeFirebase(), - builder: (context, snapshot) { - if (!snapshot.hasData) { - return const Center( - child: CircularProgressIndicator(), - ); - } - - return MaterialApp.router( - routerConfig: _router, - title: 'GoatAgent', - theme: ThemeData( - colorScheme: ColorScheme.fromSeed(seedColor: Colors.indigo), - useMaterial3: true, - ), - builder: (BuildContext context, Widget? child) { - return Overlay(initialEntries: [ - OverlayEntry( - builder: (context) => Scaffold( - body: child, - // bottomNavigationBar: const AgentBottomNavigation() - bottomNavigationBar: AgentNavigation(router: _router), - ), - ) - ]); - }, - ); + return MaterialApp.router( + routerConfig: _router, + title: 'GoatAgent', + theme: ThemeData( + colorScheme: ColorScheme.fromSeed(seedColor: Colors.indigo), + useMaterial3: true, + ), + builder: (BuildContext context, Widget? child) { + return Overlay(initialEntries: [ + OverlayEntry( + builder: (context) => Scaffold( + body: child, + // bottomNavigationBar: const AgentBottomNavigation() + bottomNavigationBar: AgentNavigation(router: _router), + ), + ) + ]); }, ); } diff --git a/lib/screens/about.dart b/lib/screens/about.dart new file mode 100644 index 0000000..3669f22 --- /dev/null +++ b/lib/screens/about.dart @@ -0,0 +1,49 @@ +import 'package:flutter/material.dart'; +import 'package:package_info_plus/package_info_plus.dart'; +import 'package:url_launcher/url_launcher.dart'; + +class AboutScreen extends StatelessWidget { + const AboutScreen({super.key}); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('About'), + ), + body: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text('GoatAgent', + style: Theme.of(context).textTheme.headlineMedium), + Text('Goatworks Official Mobile Helper', + style: Theme.of(context).textTheme.bodyLarge), + const SizedBox(height: 20), + FutureBuilder( + future: PackageInfo.fromPlatform(), + builder: (context, snapshot) { + if (snapshot.hasData) { + var version = snapshot.data!.version; + return Text('v$version', + style: Theme.of(context).textTheme.bodyLarge); + } else { + return Container(); + } + }, + ), + Text('Open sourced under GOLv1', style: Theme.of(context).textTheme.bodyMedium), + const SizedBox(height: 10), + MaterialButton( + onPressed: () async { + await launchUrl(Uri.parse('https://smartsheep.studio')); + }, + child: const Text('Official Website'), + ), + ], + ), + ), + ); + } +} diff --git a/lib/screens/account.dart b/lib/screens/account.dart index 079b701..9e46be9 100644 --- a/lib/screens/account.dart +++ b/lib/screens/account.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; import 'package:goatagent/auth.dart'; import 'package:goatagent/widgets/name_card.dart'; @@ -28,57 +29,67 @@ class _AccountScreenState extends State { body: SafeArea( child: Padding( padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 20), - child: Column( - children: [ - Padding( - padding: const EdgeInsets.only(top: 20), - child: NameCard( - onLogin: () async { - await AuthGuard().login(context); - var authorized = await AuthGuard().isAuthorized(); - setState(() { - isAuthorized = authorized; - }); - }, - ), - ), - FutureBuilder( - future: AuthGuard().isAuthorized(), - builder: (BuildContext context, AsyncSnapshot snapshot) { - if (snapshot.hasData && snapshot.data == true) { - return Padding( - padding: const EdgeInsets.only(top: 5), - child: Wrap( - spacing: 5, - children: [ - Card( - elevation: 0, - child: InkWell( - splashColor: Colors.indigo.withAlpha(30), - onTap: () async { - AuthGuard().logout(); - var authorized = - await AuthGuard().isAuthorized(); - setState(() { - isAuthorized = authorized; - }); - }, - child: const ListTile( - leading: Icon(Icons.logout), - title: Text('Logout'), - ), - ), - ), - ], - ), - ); - } else { - return const Padding(padding: EdgeInsets.only(top: 5)); - } + child: Column(children: [ + Padding( + padding: const EdgeInsets.only(top: 20), + child: NameCard( + onLogin: () async { + await AuthGuard().login(context); + var authorized = await AuthGuard().isAuthorized(); + setState(() { + isAuthorized = authorized; + }); }, ), - ], - ), + ), + Padding( + padding: const EdgeInsets.only(top: 5), + child: Wrap( + spacing: 5, + children: [ + FutureBuilder( + future: AuthGuard().isAuthorized(), + builder: (BuildContext context, AsyncSnapshot snapshot) { + if (snapshot.hasData && snapshot.data == true) { + return Card( + elevation: 0, + child: InkWell( + splashColor: Colors.indigo.withAlpha(30), + onTap: () async { + AuthGuard().logout(); + var authorized = await AuthGuard().isAuthorized(); + setState(() { + isAuthorized = authorized; + }); + }, + child: const ListTile( + leading: Icon(Icons.logout), + title: Text('Logout'), + ), + ), + ); + } else { + return Container(); + } + }, + ), + Card( + elevation: 0, + child: InkWell( + splashColor: Colors.indigo.withAlpha(30), + onTap: () { + GoRouter.of(context).push("/about"); + }, + child: const ListTile( + leading: Icon(Icons.info_outline), + title: Text('About'), + ), + ), + ), + ], + ), + ), + ]), ), ), ); diff --git a/linux/flutter/generated_plugin_registrant.cc b/linux/flutter/generated_plugin_registrant.cc index d0e7f79..38dd0bc 100644 --- a/linux/flutter/generated_plugin_registrant.cc +++ b/linux/flutter/generated_plugin_registrant.cc @@ -7,9 +7,13 @@ #include "generated_plugin_registrant.h" #include +#include void fl_register_plugins(FlPluginRegistry* registry) { g_autoptr(FlPluginRegistrar) flutter_secure_storage_linux_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterSecureStorageLinuxPlugin"); flutter_secure_storage_linux_plugin_register_with_registrar(flutter_secure_storage_linux_registrar); + g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin"); + url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar); } diff --git a/linux/flutter/generated_plugins.cmake b/linux/flutter/generated_plugins.cmake index b29e9ba..65240e9 100644 --- a/linux/flutter/generated_plugins.cmake +++ b/linux/flutter/generated_plugins.cmake @@ -4,6 +4,7 @@ list(APPEND FLUTTER_PLUGIN_LIST flutter_secure_storage_linux + url_launcher_linux ) list(APPEND FLUTTER_FFI_PLUGIN_LIST diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 64fad2b..2bb1105 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -10,7 +10,9 @@ import firebase_crashlytics import firebase_messaging import flutter_appauth import flutter_secure_storage_macos +import package_info_plus import path_provider_foundation +import url_launcher_macos func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin")) @@ -18,5 +20,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { FLTFirebaseMessagingPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseMessagingPlugin")) FlutterAppauthPlugin.register(with: registry.registrar(forPlugin: "FlutterAppauthPlugin")) FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin")) + FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) + UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) } diff --git a/pubspec.lock b/pubspec.lock index dd0cebe..fc3d90c 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -376,6 +376,22 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.2" + package_info_plus: + dependency: "direct main" + description: + name: package_info_plus + sha256: "88bc797f44a94814f2213db1c9bd5badebafdfb8290ca9f78d4b9ee2a3db4d79" + url: "https://pub.dev" + source: hosted + version: "5.0.1" + package_info_plus_platform_interface: + dependency: transitive + description: + name: package_info_plus_platform_interface + sha256: "9bc8ba46813a4cc42c66ab781470711781940780fd8beddd0c3da62506d3a6c6" + url: "https://pub.dev" + source: hosted + version: "2.0.1" path: dependency: transitive description: @@ -525,6 +541,70 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.2" + url_launcher: + dependency: "direct main" + description: + name: url_launcher + sha256: c512655380d241a337521703af62d2c122bf7b77a46ff7dd750092aa9433499c + url: "https://pub.dev" + source: hosted + version: "6.2.4" + url_launcher_android: + dependency: transitive + description: + name: url_launcher_android + sha256: "507dc655b1d9cb5ebc756032eb785f114e415f91557b73bf60b7e201dfedeb2f" + url: "https://pub.dev" + source: hosted + version: "6.2.2" + url_launcher_ios: + dependency: transitive + description: + name: url_launcher_ios + sha256: "75bb6fe3f60070407704282a2d295630cab232991eb52542b18347a8a941df03" + url: "https://pub.dev" + source: hosted + version: "6.2.4" + url_launcher_linux: + dependency: transitive + description: + name: url_launcher_linux + sha256: ab360eb661f8879369acac07b6bb3ff09d9471155357da8443fd5d3cf7363811 + url: "https://pub.dev" + source: hosted + version: "3.1.1" + url_launcher_macos: + dependency: transitive + description: + name: url_launcher_macos + sha256: b7244901ea3cf489c5335bdacda07264a6e960b1c1b1a9f91e4bc371d9e68234 + url: "https://pub.dev" + source: hosted + version: "3.1.0" + url_launcher_platform_interface: + dependency: transitive + description: + name: url_launcher_platform_interface + sha256: a932c3a8082e118f80a475ce692fde89dc20fddb24c57360b96bc56f7035de1f + url: "https://pub.dev" + source: hosted + version: "2.3.1" + url_launcher_web: + dependency: transitive + description: + name: url_launcher_web + sha256: fff0932192afeedf63cdd50ecbb1bc825d31aed259f02bb8dba0f3b729a5e88b + url: "https://pub.dev" + source: hosted + version: "2.2.3" + url_launcher_windows: + dependency: transitive + description: + name: url_launcher_windows + sha256: ecf9725510600aa2bb6d7ddabe16357691b6d2805f66216a97d1b881e21beff7 + url: "https://pub.dev" + source: hosted + version: "3.1.1" vector_math: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 531b8bd..4b01f77 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -44,6 +44,8 @@ dependencies: http: ^1.2.0 webview_flutter: ^4.5.0 go_router: ^13.1.0 + package_info_plus: ^5.0.1 + url_launcher: ^6.2.4 dev_dependencies: flutter_test: diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index 39cedd3..0e0afee 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -8,10 +8,13 @@ #include #include +#include void RegisterPlugins(flutter::PluginRegistry* registry) { FirebaseCorePluginCApiRegisterWithRegistrar( registry->GetRegistrarForPlugin("FirebaseCorePluginCApi")); FlutterSecureStorageWindowsPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("FlutterSecureStorageWindowsPlugin")); + UrlLauncherWindowsRegisterWithRegistrar( + registry->GetRegistrarForPlugin("UrlLauncherWindows")); } diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index 1f5d05f..9efea82 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -5,6 +5,7 @@ list(APPEND FLUTTER_PLUGIN_LIST firebase_core flutter_secure_storage_windows + url_launcher_windows ) list(APPEND FLUTTER_FFI_PLUGIN_LIST