diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts index b704371..f263269 100644 --- a/android/app/build.gradle.kts +++ b/android/app/build.gradle.kts @@ -6,7 +6,7 @@ plugins { } android { - namespace = "xyz.dailitation.linesofcodes.liteauthconfig.liteauthconfig" + namespace = "xyz.dailitation.linesofcodes.liteauthconfig" compileSdk = flutter.compileSdkVersion ndkVersion = flutter.ndkVersion @@ -15,13 +15,15 @@ android { targetCompatibility = JavaVersion.VERSION_11 } - kotlinOptions { - jvmTarget = JavaVersion.VERSION_11.toString() + kotlin { + compilerOptions { + jvmTarget = org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_11 + } } defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). - applicationId = "xyz.dailitation.linesofcodes.liteauthconfig.liteauthconfig" + applicationId = "xyz.dailitation.linesofcodes.liteauthconfig" // 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/xyz/dailitation/linesofcodes/liteauthconfig/liteauthconfig/MainActivity.kt b/android/app/src/main/kotlin/xyz/dailitation/linesofcodes/liteauthconfig/MainActivity.kt similarity index 58% rename from android/app/src/main/kotlin/xyz/dailitation/linesofcodes/liteauthconfig/liteauthconfig/MainActivity.kt rename to android/app/src/main/kotlin/xyz/dailitation/linesofcodes/liteauthconfig/MainActivity.kt index 9a76ed2..411fb3b 100644 --- a/android/app/src/main/kotlin/xyz/dailitation/linesofcodes/liteauthconfig/liteauthconfig/MainActivity.kt +++ b/android/app/src/main/kotlin/xyz/dailitation/linesofcodes/liteauthconfig/MainActivity.kt @@ -1,4 +1,4 @@ -package xyz.dailitation.linesofcodes.liteauthconfig.liteauthconfig +package xyz.dailitation.linesofcodes.liteauthconfig import io.flutter.embedding.android.FlutterActivity diff --git a/android/build/reports/problems/problems-report.html b/android/build/reports/problems/problems-report.html new file mode 100644 index 0000000..c0feb4e --- /dev/null +++ b/android/build/reports/problems/problems-report.html @@ -0,0 +1,663 @@ + + + + + + + + + + + + + Gradle Configuration Cache + + + +
+ +
+ Loading... +
+ + + + + + diff --git a/android/settings.gradle.kts b/android/settings.gradle.kts index 93d6cd2..68fe453 100644 --- a/android/settings.gradle.kts +++ b/android/settings.gradle.kts @@ -19,8 +19,8 @@ pluginManagement { plugins { id("dev.flutter.flutter-plugin-loader") version "1.0.0" - id("com.android.application") version "8.13.0" apply false - id("org.jetbrains.kotlin.android") version "2.2.21" apply false + id("com.android.application") version "8.13.2" apply false + id("org.jetbrains.kotlin.android") version "2.3.0" apply false } include(":app") diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 9a1256a..94b623e 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -368,7 +368,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = xyz.dailitation.linesofcodes.liteauthconfig.liteauthconfig; + PRODUCT_BUNDLE_IDENTIFIER = xyz.dailitation.linesofcodes.liteauthconfig; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; @@ -384,7 +384,7 @@ CURRENT_PROJECT_VERSION = 1; GENERATE_INFOPLIST_FILE = YES; MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = xyz.dailitation.linesofcodes.liteauthconfig.liteauthconfig.RunnerTests; + PRODUCT_BUNDLE_IDENTIFIER = xyz.dailitation.linesofcodes.liteauthconfig.RunnerTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; @@ -401,7 +401,7 @@ CURRENT_PROJECT_VERSION = 1; GENERATE_INFOPLIST_FILE = YES; MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = xyz.dailitation.linesofcodes.liteauthconfig.liteauthconfig.RunnerTests; + PRODUCT_BUNDLE_IDENTIFIER = xyz.dailitation.linesofcodes.liteauthconfig.RunnerTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; @@ -416,7 +416,7 @@ CURRENT_PROJECT_VERSION = 1; GENERATE_INFOPLIST_FILE = YES; MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = xyz.dailitation.linesofcodes.liteauthconfig.liteauthconfig.RunnerTests; + PRODUCT_BUNDLE_IDENTIFIER = xyz.dailitation.linesofcodes.liteauthconfig.RunnerTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; @@ -547,7 +547,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = xyz.dailitation.linesofcodes.liteauthconfig.liteauthconfig; + PRODUCT_BUNDLE_IDENTIFIER = xyz.dailitation.linesofcodes.liteauthconfig; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; @@ -569,7 +569,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = xyz.dailitation.linesofcodes.liteauthconfig.liteauthconfig; + PRODUCT_BUNDLE_IDENTIFIER = xyz.dailitation.linesofcodes.liteauthconfig; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index 68e84e0..3b7e3b8 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -47,5 +47,8 @@ NFCReaderUsageDescription Interacting with the liteauth device + + NSCameraUsageDescription + This app needs camera access to scan QR codes diff --git a/lib/dialogs/esptouchdialog.dart b/lib/dialogs/esptouchdialog.dart index e92c2c3..7b8d5e4 100644 --- a/lib/dialogs/esptouchdialog.dart +++ b/lib/dialogs/esptouchdialog.dart @@ -43,6 +43,8 @@ class _ESPTouchDialog extends State { final touchStream = task.execute(); final sub = touchStream.listen((data) async { + var conf = AppConfig(); + final dev = Device( name: widget.name, routerSsid: widget.ssid, @@ -50,11 +52,14 @@ class _ESPTouchDialog extends State { networkPassword: widget.password, ); + if (widget.entryIndex != null) { + final oldDev = conf.devices[widget.entryIndex!]; + dev.token = oldDev.token; + } + dev.ip = data.ip; dev.bssid = data.bssid; - var conf = AppConfig(); - if (widget.addNewEntry) { conf.devices.add(dev); } else { diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index cdd504d..a4d13a1 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -29,13 +29,31 @@ "deletion": "Deletion", "deviceDeleteConfirm": "Are you sure you want to delete this device forever?", "reconfigureNetwork": "Reconfigure Network", - "factoryReset": "Factory Reset", - "resetConfirm": "Are you sure you want to proceed with the factory reset? Your data will be lost and unrecoverable, and you must setup the device again.", - "reset": "Reset", "status": "Status: ", "online": "Online", "offline": "Offline", "refresh": "Refresh", + "cannotBeEmpty": "{field} cannot be empty!", + "@cannotBeEmpty": { + "placeholders": { + "field": { + "type": "String", + "example": "SSID" + } + } + }, + "tokenForbidden": "Token cannot be requested. Please manually enter the token or physically factory reset the device.", + "requestFailedWithCode": "Request failed with code {code}", + "@requestFailedWithCode": { + "placeholders": { + "code": { + "type": "int", + "example": "400" + } + } + }, + "additionalActions": "Additional Actions", + "dangerousActions": "Dangerous Actions", "lastKnownIP": "Last Known IP: {ip}", "@lastKnownIP": { "placeholders": { @@ -54,5 +72,29 @@ } } }, - "activityLogs": "Activity Logs" + "activityLogs": "Activity Logs", + + "factoryReset": "Factory Reset", + "resetConfirm": "Are you sure you want to proceed with the factory reset? Your data will be lost and unrecoverable, and you must setup the device again.", + "reset": "Reset", + "resetSuccessful": "Reset Successful", + "resetFailedCode": "Reset failed with code {code}", + "@resetFailedCode": { + "placeholders": { + "code": { + "type": "int", + "example": "400" + } + } + }, + + "token": "Token", + "manageToken": "Manage Token", + "tokenNotFound": "Token not found. Please enter one or do a manual factory reset.", + "viewTokenWarn": "Tokens are sensitive. Please do not share this token publicly.", + "showToken": "Show Token", + "copyToken": "Copy Token", + "copied": "Copied", + "saveToken": "Save Token", + "saved": "Saved!" } \ No newline at end of file diff --git a/lib/l10n/app_localizations.dart b/lib/l10n/app_localizations.dart index a30a73c..df96840 100644 --- a/lib/l10n/app_localizations.dart +++ b/lib/l10n/app_localizations.dart @@ -260,24 +260,6 @@ abstract class AppLocalizations { /// **'Reconfigure Network'** String get reconfigureNetwork; - /// No description provided for @factoryReset. - /// - /// In en, this message translates to: - /// **'Factory Reset'** - String get factoryReset; - - /// No description provided for @resetConfirm. - /// - /// In en, this message translates to: - /// **'Are you sure you want to proceed with the factory reset? Your data will be lost and unrecoverable, and you must setup the device again.'** - String get resetConfirm; - - /// No description provided for @reset. - /// - /// In en, this message translates to: - /// **'Reset'** - String get reset; - /// No description provided for @status. /// /// In en, this message translates to: @@ -302,6 +284,36 @@ abstract class AppLocalizations { /// **'Refresh'** String get refresh; + /// No description provided for @cannotBeEmpty. + /// + /// In en, this message translates to: + /// **'{field} cannot be empty!'** + String cannotBeEmpty(String field); + + /// No description provided for @tokenForbidden. + /// + /// In en, this message translates to: + /// **'Token cannot be requested. Please manually enter the token or physically factory reset the device.'** + String get tokenForbidden; + + /// No description provided for @requestFailedWithCode. + /// + /// In en, this message translates to: + /// **'Request failed with code {code}'** + String requestFailedWithCode(int code); + + /// No description provided for @additionalActions. + /// + /// In en, this message translates to: + /// **'Additional Actions'** + String get additionalActions; + + /// No description provided for @dangerousActions. + /// + /// In en, this message translates to: + /// **'Dangerous Actions'** + String get dangerousActions; + /// No description provided for @lastKnownIP. /// /// In en, this message translates to: @@ -319,6 +331,90 @@ abstract class AppLocalizations { /// In en, this message translates to: /// **'Activity Logs'** String get activityLogs; + + /// No description provided for @factoryReset. + /// + /// In en, this message translates to: + /// **'Factory Reset'** + String get factoryReset; + + /// No description provided for @resetConfirm. + /// + /// In en, this message translates to: + /// **'Are you sure you want to proceed with the factory reset? Your data will be lost and unrecoverable, and you must setup the device again.'** + String get resetConfirm; + + /// No description provided for @reset. + /// + /// In en, this message translates to: + /// **'Reset'** + String get reset; + + /// No description provided for @resetSuccessful. + /// + /// In en, this message translates to: + /// **'Reset Successful'** + String get resetSuccessful; + + /// No description provided for @resetFailedCode. + /// + /// In en, this message translates to: + /// **'Reset failed with code {code}'** + String resetFailedCode(int code); + + /// No description provided for @token. + /// + /// In en, this message translates to: + /// **'Token'** + String get token; + + /// No description provided for @manageToken. + /// + /// In en, this message translates to: + /// **'Manage Token'** + String get manageToken; + + /// No description provided for @tokenNotFound. + /// + /// In en, this message translates to: + /// **'Token not found. Please enter one or do a manual factory reset.'** + String get tokenNotFound; + + /// No description provided for @viewTokenWarn. + /// + /// In en, this message translates to: + /// **'Tokens are sensitive. Please do not share this token publicly.'** + String get viewTokenWarn; + + /// No description provided for @showToken. + /// + /// In en, this message translates to: + /// **'Show Token'** + String get showToken; + + /// No description provided for @copyToken. + /// + /// In en, this message translates to: + /// **'Copy Token'** + String get copyToken; + + /// No description provided for @copied. + /// + /// In en, this message translates to: + /// **'Copied'** + String get copied; + + /// No description provided for @saveToken. + /// + /// In en, this message translates to: + /// **'Save Token'** + String get saveToken; + + /// No description provided for @saved. + /// + /// In en, this message translates to: + /// **'Saved!'** + String get saved; } class _AppLocalizationsDelegate diff --git a/lib/l10n/app_localizations_en.dart b/lib/l10n/app_localizations_en.dart index a498c6e..cb82f5b 100644 --- a/lib/l10n/app_localizations_en.dart +++ b/lib/l10n/app_localizations_en.dart @@ -96,16 +96,6 @@ class AppLocalizationsEn extends AppLocalizations { @override String get reconfigureNetwork => 'Reconfigure Network'; - @override - String get factoryReset => 'Factory Reset'; - - @override - String get resetConfirm => - 'Are you sure you want to proceed with the factory reset? Your data will be lost and unrecoverable, and you must setup the device again.'; - - @override - String get reset => 'Reset'; - @override String get status => 'Status: '; @@ -118,6 +108,26 @@ class AppLocalizationsEn extends AppLocalizations { @override String get refresh => 'Refresh'; + @override + String cannotBeEmpty(String field) { + return '$field cannot be empty!'; + } + + @override + String get tokenForbidden => + 'Token cannot be requested. Please manually enter the token or physically factory reset the device.'; + + @override + String requestFailedWithCode(int code) { + return 'Request failed with code $code'; + } + + @override + String get additionalActions => 'Additional Actions'; + + @override + String get dangerousActions => 'Dangerous Actions'; + @override String lastKnownIP(String ip) { return 'Last Known IP: $ip'; @@ -130,4 +140,51 @@ class AppLocalizationsEn extends AppLocalizations { @override String get activityLogs => 'Activity Logs'; + + @override + String get factoryReset => 'Factory Reset'; + + @override + String get resetConfirm => + 'Are you sure you want to proceed with the factory reset? Your data will be lost and unrecoverable, and you must setup the device again.'; + + @override + String get reset => 'Reset'; + + @override + String get resetSuccessful => 'Reset Successful'; + + @override + String resetFailedCode(int code) { + return 'Reset failed with code $code'; + } + + @override + String get token => 'Token'; + + @override + String get manageToken => 'Manage Token'; + + @override + String get tokenNotFound => + 'Token not found. Please enter one or do a manual factory reset.'; + + @override + String get viewTokenWarn => + 'Tokens are sensitive. Please do not share this token publicly.'; + + @override + String get showToken => 'Show Token'; + + @override + String get copyToken => 'Copy Token'; + + @override + String get copied => 'Copied'; + + @override + String get saveToken => 'Save Token'; + + @override + String get saved => 'Saved!'; } diff --git a/lib/l10n/app_localizations_th.dart b/lib/l10n/app_localizations_th.dart index 874d059..7f25708 100644 --- a/lib/l10n/app_localizations_th.dart +++ b/lib/l10n/app_localizations_th.dart @@ -95,16 +95,6 @@ class AppLocalizationsTh extends AppLocalizations { @override String get reconfigureNetwork => 'ตั้งค่าเครือข่ายใหม่'; - @override - String get factoryReset => 'คืนค่าโรงงาน'; - - @override - String get resetConfirm => - 'คุณแน่ใจหรือไม่ว่าต้องการคืนค่าจากโรงงาน ข้อมูลของคุณจะหายไปและไม่สามารถกู้คืนได้ และคุณจำเป็นต้องตั้งค่าอุปกรณ์ใหม่'; - - @override - String get reset => 'คืนค่า'; - @override String get status => 'สถานะ: '; @@ -117,6 +107,26 @@ class AppLocalizationsTh extends AppLocalizations { @override String get refresh => 'รีเฟรช'; + @override + String cannotBeEmpty(String field) { + return '$field ไม่สามารถเป็นค่าว่างได้!'; + } + + @override + String get tokenForbidden => + 'ไม่สามารถรับค่าโทเค็นได้ โปรดใส่โทเค็นด้วยตนเองหรือคืนค่าโรงงานอุปกรณ์'; + + @override + String requestFailedWithCode(int code) { + return 'คำขอล้มเหลวด้วยรหัส $code'; + } + + @override + String get additionalActions => 'การกระทำเพิ่มเติม'; + + @override + String get dangerousActions => 'การกระทำอันตราย'; + @override String lastKnownIP(String ip) { return 'ที่อยู่ IP ที่ทราบล่าสุด: $ip'; @@ -129,4 +139,51 @@ class AppLocalizationsTh extends AppLocalizations { @override String get activityLogs => 'รายการกิจกรรม'; + + @override + String get factoryReset => 'คืนค่าโรงงาน'; + + @override + String get resetConfirm => + 'คุณแน่ใจหรือไม่ว่าต้องการคืนค่าจากโรงงาน ข้อมูลของคุณจะหายไปและไม่สามารถกู้คืนได้ และคุณจำเป็นต้องตั้งค่าอุปกรณ์ใหม่'; + + @override + String get reset => 'คืนค่า'; + + @override + String get resetSuccessful => 'คืนค่าสำเร็จ'; + + @override + String resetFailedCode(int code) { + return 'การคืนค่าล้มเหลวด้วยรหัส $code'; + } + + @override + String get token => 'โทเค็น'; + + @override + String get manageToken => 'จัดการโทเค็น'; + + @override + String get tokenNotFound => + 'ไม่พบโทเค็น โปรดใส่โทเค็นหรือทำการคืนค่าโรงงานด้วยตนเอง'; + + @override + String get viewTokenWarn => + 'โทเค็นเป็นข้อมูลละเอียดอ่อน โปรดอย่าเผยแพร่โทเค็นของคุณ'; + + @override + String get showToken => 'แสดงโทเค็น'; + + @override + String get copyToken => 'คัดลอกโทเค็น'; + + @override + String get copied => 'คัดลอกแล้ว'; + + @override + String get saveToken => 'บันทึกโทเค็น'; + + @override + String get saved => 'บันทึกแล้ว'; } diff --git a/lib/l10n/app_th.arb b/lib/l10n/app_th.arb index 71a9c00..d7ca26c 100644 --- a/lib/l10n/app_th.arb +++ b/lib/l10n/app_th.arb @@ -29,14 +29,32 @@ "deletion": "การลบ", "deviceDeleteConfirm": "คุณแน่ใจหรือไม่ที่จะลบอุปกรณ์นี้อย่างถาวร", "reconfigureNetwork": "ตั้งค่าเครือข่ายใหม่", - "factoryReset": "คืนค่าโรงงาน", - "resetConfirm": "คุณแน่ใจหรือไม่ว่าต้องการคืนค่าจากโรงงาน ข้อมูลของคุณจะหายไปและไม่สามารถกู้คืนได้ และคุณจำเป็นต้องตั้งค่าอุปกรณ์ใหม่", - "reset": "คืนค่า", "status": "สถานะ: ", "online": "ออนไลน์", "offline": "ออฟไลน์", "refresh": "รีเฟรช", + "cannotBeEmpty": "{field} ไม่สามารถเป็นค่าว่างได้!", + "tokenForbidden": "ไม่สามารถรับค่าโทเค็นได้ โปรดใส่โทเค็นด้วยตนเองหรือคืนค่าโรงงานอุปกรณ์", + "requestFailedWithCode": "คำขอล้มเหลวด้วยรหัส {code}", + "additionalActions": "การกระทำเพิ่มเติม", + "dangerousActions": "การกระทำอันตราย", "lastKnownIP": "ที่อยู่ IP ที่ทราบล่าสุด: {ip}", "routerSsid": "SSID เราเตอร์: {ssid}", - "activityLogs": "รายการกิจกรรม" + "activityLogs": "รายการกิจกรรม", + + "factoryReset": "คืนค่าโรงงาน", + "resetConfirm": "คุณแน่ใจหรือไม่ว่าต้องการคืนค่าจากโรงงาน ข้อมูลของคุณจะหายไปและไม่สามารถกู้คืนได้ และคุณจำเป็นต้องตั้งค่าอุปกรณ์ใหม่", + "reset": "คืนค่า", + "resetSuccessful": "คืนค่าสำเร็จ", + "resetFailedCode": "การคืนค่าล้มเหลวด้วยรหัส {code}", + + "token": "โทเค็น", + "manageToken": "จัดการโทเค็น", + "tokenNotFound": "ไม่พบโทเค็น โปรดใส่โทเค็นหรือทำการคืนค่าโรงงานด้วยตนเอง", + "viewTokenWarn": "โทเค็นเป็นข้อมูลละเอียดอ่อน โปรดอย่าเผยแพร่โทเค็นของคุณ", + "showToken": "แสดงโทเค็น", + "copyToken": "คัดลอกโทเค็น", + "copied": "คัดลอกแล้ว", + "saveToken": "บันทึกโทเค็น", + "saved": "บันทึกแล้ว" } \ No newline at end of file diff --git a/lib/main.dart b/lib/main.dart index 070651c..563d35d 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -49,7 +49,6 @@ class MyApp extends StatelessWidget { title: 'liteauthconfig', localizationsDelegates: AppLocalizations.localizationsDelegates, supportedLocales: AppLocalizations.supportedLocales, - locale: Locale("th"), theme: ThemeData.light().copyWith( colorScheme: ColorScheme.fromSeed( seedColor: SystemTheme.accentColor.accent, @@ -65,6 +64,7 @@ class MyApp extends StatelessWidget { textColor: Colors.white, iconColor: Colors.white, ), + bottomSheetTheme: BottomSheetThemeData(backgroundColor: darkColors.inverseSurface) ), home: DeviceListPage(), ); diff --git a/lib/models/appconfig.dart b/lib/models/appconfig.dart index e403b03..875bebe 100644 --- a/lib/models/appconfig.dart +++ b/lib/models/appconfig.dart @@ -40,6 +40,7 @@ class Device { String routerSsid; String routerBssid; String networkPassword; + String token; String? ip; String? bssid; @@ -47,6 +48,7 @@ class Device { required this.name, required this.routerSsid, required this.routerBssid, + this.token = "", this.networkPassword = "", }); diff --git a/lib/models/appconfig.g.dart b/lib/models/appconfig.g.dart index d819495..aa87bd5 100644 --- a/lib/models/appconfig.g.dart +++ b/lib/models/appconfig.g.dart @@ -20,6 +20,7 @@ Device _$DeviceFromJson(Map json) => name: json['name'] as String, routerSsid: json['routerSsid'] as String, routerBssid: json['routerBssid'] as String, + token: json['token'] as String? ?? "", networkPassword: json['networkPassword'] as String? ?? "", ) ..ip = json['ip'] as String? @@ -30,6 +31,7 @@ Map _$DeviceToJson(Device instance) => { 'routerSsid': instance.routerSsid, 'routerBssid': instance.routerBssid, 'networkPassword': instance.networkPassword, + 'token': instance.token, 'ip': instance.ip, 'bssid': instance.bssid, }; diff --git a/lib/models/device_status.g.dart b/lib/models/device_status.g.dart new file mode 100644 index 0000000..b1d5bde --- /dev/null +++ b/lib/models/device_status.g.dart @@ -0,0 +1,18 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'device_status.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +DeviceStatus _$DeviceStatusFromJson(Map json) => DeviceStatus( + entryNfc: json['entryNfc'] as bool? ?? false, + exitNfc: json['exitNfc'] as bool? ?? false, +); + +Map _$DeviceStatusToJson(DeviceStatus instance) => + { + 'entryNfc': instance.entryNfc, + 'exitNfc': instance.exitNfc, + }; diff --git a/lib/models/logentry.dart b/lib/models/logentry.dart new file mode 100644 index 0000000..dbde823 --- /dev/null +++ b/lib/models/logentry.dart @@ -0,0 +1,16 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'logentry.g.dart'; + +@JsonSerializable() +class LogEntry { + DateTime time; + String uid; + + LogEntry({required this.time, required this.uid}); + + factory LogEntry.fromJson(Map json) => + _$LogEntryFromJson(json); + + Map toJson() => _$LogEntryToJson(this); +} diff --git a/lib/models/logentry.g.dart b/lib/models/logentry.g.dart new file mode 100644 index 0000000..069549f --- /dev/null +++ b/lib/models/logentry.g.dart @@ -0,0 +1,17 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'logentry.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +LogEntry _$LogEntryFromJson(Map json) => LogEntry( + time: DateTime.parse(json['time'] as String), + uid: json['uid'] as String, +); + +Map _$LogEntryToJson(LogEntry instance) => { + 'time': instance.time.toIso8601String(), + 'uid': instance.uid, +}; diff --git a/lib/pages/deviceinfo.dart b/lib/pages/deviceinfo.dart index e10d05b..660db18 100644 --- a/lib/pages/deviceinfo.dart +++ b/lib/pages/deviceinfo.dart @@ -1,11 +1,15 @@ import 'dart:async'; -import 'dart:convert'; +import 'dart:io'; +import 'package:dio/dio.dart'; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:liteauthconfig/models/appconfig.dart'; import 'package:liteauthconfig/l10n/app_localizations.dart'; import 'package:liteauthconfig/models/device_status.dart'; +import 'package:liteauthconfig/models/logentry.dart'; import 'package:liteauthconfig/pages/reconfigure_network.dart'; +import 'package:liteauthconfig/pages/tokeninfo.dart'; import 'package:liteauthconfig/utils/network.dart'; class DeviceInfoPage extends StatefulWidget { @@ -17,13 +21,18 @@ class DeviceInfoPage extends StatefulWidget { State createState() => _DeviceInfoPageState(); } +enum TokenState { requesting, exists, error } + class _DeviceInfoPageState extends State { + late Dio httpClient; late Device device; DeviceStatus? deviceStatus; String statusMessage = ""; bool online = false; bool loading = false; Timer? refreshTimer; + late Timer logPollTimer; + List logEntries = []; @override void initState() { @@ -31,40 +40,67 @@ class _DeviceInfoPageState extends State { refreshDevice(); checkStatus(); + logPollTimer = Timer.periodic( + Duration(seconds: 15), + (timer) => queryLogs(), + ); } void refreshDevice() { device = AppConfig().devices[widget.deviceIndex]; } + Future checkToken() async { + var appLocal = AppLocalizations.of(context)!; + var resp = await httpClient.get("https://liteauth.local/api/getToken"); + + if (resp.statusCode != 200) { + statusMessage = appLocal.tokenForbidden; + return; + } + + device.token = resp.data; + final config = AppConfig(); + config.devices[widget.deviceIndex] = device; + await config.save(); + } + Future checkStatus() async { statusMessage = ""; setState(() { loading = true; }); - var client = await createEspHttpClient(); + httpClient = await createEspHttpClient(token: device.token); try { - var resp = await client.get( - Uri.parse("https://liteauth.local/api/status"), - ); - deviceStatus = DeviceStatus.fromJson(jsonDecode(resp.body)); - online = resp.statusCode >= 200 && resp.statusCode < 300; + var resp = await httpClient.get("https://liteauth.local/api/status"); + deviceStatus = DeviceStatus.fromJson(resp.data); + online = resp.statusCode! >= 200 && resp.statusCode! < 300; } catch (e) { statusMessage = e.toString(); online = false; - refreshTimer ??= Timer.periodic(const Duration(seconds: 5), ( + refreshTimer ??= Timer.periodic(const Duration(seconds: 10), ( timer, ) async { + if (loading) return; await checkStatus(); if (online) { + statusMessage = ""; timer.cancel(); refreshTimer = null; } }); } + if (online && device.token.isEmpty) { + try { + await checkToken(); + } catch (e) { + statusMessage = e.toString(); + } + } + if (mounted) { setState(() { loading = false; @@ -75,28 +111,96 @@ class _DeviceInfoPageState extends State { void factoryReset() async { var appLocal = AppLocalizations.of(context)!; - var reset = await showDialog(context: context, builder: (ctx) => AlertDialog.adaptive( - title: Text(appLocal.factoryReset), - content: Text(appLocal.resetConfirm), - actions: [ - TextButton(onPressed: () { - Navigator.of(ctx).pop(false); - }, child: Text(appLocal.cancel)), - TextButton(onPressed: () { - Navigator.of(ctx).pop(true); - }, child: Text(appLocal.reset)), - ], - )) ?? false; + var reset = + await showDialog( + context: context, + builder: (ctx) => AlertDialog.adaptive( + title: Text(appLocal.factoryReset), + content: Text(appLocal.resetConfirm), + actions: [ + TextButton( + onPressed: () { + Navigator.of(ctx).pop(false); + }, + child: Text(appLocal.cancel), + ), + TextButton( + onPressed: () { + Navigator.of(ctx).pop(true); + }, + child: Text(appLocal.reset), + ), + ], + ), + ) ?? + false; if (!reset) return; - var client = await createEspHttpClient(); - client.get(Uri.parse("https://liteauth.local/api/factoryReset")); + if (!mounted) { + return; + } + + Navigator.pop(context); + + setState(() { + loading = true; + }); + final resp = await httpClient.get( + "https://liteauth.local/api/factoryReset", + ); + setState(() { + loading = false; + }); + + if (resp.statusCode != 200 && mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text(appLocal.resetFailedCode(resp.statusCode!))), + ); + return; + } + + if (mounted) { + ScaffoldMessenger.of( + context, + ).showSnackBar(SnackBar(content: Text(appLocal.resetSuccessful))); + } + + device.token = ""; + var config = AppConfig(); + config.devices[widget.deviceIndex] = device; + await config.save(); + reconfigureNetwork(); + } + + void queryLogs() async { + if (!online) return; + + setState(() { + loading = true; + }); + + try { + var resp = await httpClient.get("https://liteauth.local/api/logs"); + print(DateTime.now().toIso8601String()); + logEntries = (resp.data as List).reversed + .map((data) => LogEntry.fromJson(data)) + .toList(); + } catch (e) { + if (kDebugMode) { + print(e); + } + } + + setState(() { + loading = false; + }); } @override void dispose() { refreshTimer?.cancel(); + logPollTimer.cancel(); super.dispose(); } @@ -115,81 +219,7 @@ class _DeviceInfoPageState extends State { ) : null, actions: [ - MenuAnchor( - builder: (context, controller, child) { - return IconButton( - onPressed: () { - if (controller.isOpen) { - controller.close(); - } else { - controller.open(); - } - }, - icon: Icon(Icons.adaptive.more), - ); - }, - menuChildren: [ - MenuItemButton( - leadingIcon: const Icon(Icons.refresh), - onPressed: checkStatus, - child: Text(appLocal.refresh), - ), - MenuItemButton( - leadingIcon: const Icon(Icons.network_wifi), - child: Text(appLocal.reconfigureNetwork), - onPressed: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => - ReconfigureNetworkPage(widget.deviceIndex), - ), - ).then((result) { - if (result) { - refreshDevice(); - checkStatus(); - } - }); - }, - ), - MenuItemButton( - leadingIcon: const Icon(Icons.history), - child: Text(appLocal.factoryReset), - onPressed: factoryReset, - ), - MenuItemButton( - leadingIcon: const Icon(Icons.delete), - child: Text(appLocal.delete), - onPressed: () { - showDialog( - context: context, - builder: (context) => AlertDialog.adaptive( - title: Text(appLocal.deletion), - content: Text(appLocal.deviceDeleteConfirm), - actions: [ - TextButton( - onPressed: () { - Navigator.pop(context); - }, - child: Text(appLocal.cancel), - ), - TextButton( - onPressed: () { - AppConfig() - ..devices.removeAt(widget.deviceIndex) - ..save(); - Navigator.pop(context); - Navigator.pop(context); - }, - child: Text(appLocal.delete), - ), - ], - ), - ); - }, - ), - ], - ), + IconButton(onPressed: moreActions, icon: Icon(Icons.adaptive.more)), ], ), body: SingleChildScrollView( @@ -251,6 +281,25 @@ class _DeviceInfoPageState extends State { ), ], ), + ListView.builder( + shrinkWrap: true, + itemCount: logEntries.length, + itemBuilder: (ctx, idx) { + var entry = logEntries[idx]; + return Row( + spacing: 8, + children: [ + Text( + // DateFormat.yMd().add_jms().format( + // entry.time.toLocal(), + // ), + entry.time.toIso8601String(), + ), + Text(entry.uid), + ], + ); + }, + ), ], ), ], @@ -259,4 +308,119 @@ class _DeviceInfoPageState extends State { ), ); } + + void reconfigureNetwork() { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => ReconfigureNetworkPage(widget.deviceIndex), + ), + ).then((result) { + if (result == true) { + refreshDevice(); + checkStatus(); + } + }); + } + + void moreActions() { + final appTheme = Theme.of(context); + final appLocal = AppLocalizations.of(context)!; + + showModalBottomSheet( + context: context, + builder: (ctx) => Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.fromLTRB(16, 12, 16, 0), + child: Text( + appLocal.additionalActions, + style: appTheme.textTheme.titleMedium?.copyWith( + fontWeight: FontWeight.bold, + ), + ), + ), + ListTile( + leading: const Icon(Icons.refresh), + onTap: () { + if (online) { + queryLogs(); + } else { + checkStatus(); + } + Navigator.pop(context); + }, + title: Text(appLocal.refresh), + ), + ListTile( + leading: const Icon(Icons.key), + onTap: () { + Navigator.of(ctx).push( + MaterialPageRoute( + builder: (context) => + TokenInfo(widget.deviceIndex, device.token), + ), + ); + }, + title: Text(appLocal.manageToken), + ), + Visibility( + visible: Platform.isAndroid || Platform.isIOS, + child: ListTile( + leading: const Icon(Icons.network_wifi), + title: Text(appLocal.reconfigureNetwork), + onTap: reconfigureNetwork, + ), + ), + Padding( + padding: const EdgeInsets.fromLTRB(16, 0, 16, 0), + child: Text( + appLocal.dangerousActions, + style: appTheme.textTheme.titleMedium?.copyWith( + fontWeight: FontWeight.bold, + ), + ), + ), + ListTile( + leading: const Icon(Icons.history), + title: Text(appLocal.factoryReset), + onTap: factoryReset, + ), + ListTile( + leading: const Icon(Icons.delete), + title: Text(appLocal.delete), + onTap: () { + showDialog( + context: context, + builder: (context) => AlertDialog.adaptive( + title: Text(appLocal.deletion), + content: Text(appLocal.deviceDeleteConfirm), + actions: [ + TextButton( + onPressed: () { + Navigator.pop(context); + }, + child: Text(appLocal.cancel), + ), + TextButton( + onPressed: () { + AppConfig() + ..devices.removeAt(widget.deviceIndex) + ..save(); + Navigator.pop(context); + Navigator.pop(context); + Navigator.pop(context); + }, + child: Text(appLocal.delete), + ), + ], + ), + ); + }, + ), + ], + ), + ); + } } diff --git a/lib/pages/devicelist.dart b/lib/pages/devicelist.dart index a17d76c..d56a56c 100644 --- a/lib/pages/devicelist.dart +++ b/lib/pages/devicelist.dart @@ -31,6 +31,7 @@ class _DeviceListPageState extends State { if (!(Platform.isAndroid || Platform.isIOS)) return; availability = await NfcManager.instance.checkAvailability(); + setState(() {}); if (availability != NfcAvailability.enabled) return; diff --git a/lib/pages/qrscanner.dart b/lib/pages/qrscanner.dart new file mode 100644 index 0000000..8e8ed50 --- /dev/null +++ b/lib/pages/qrscanner.dart @@ -0,0 +1,16 @@ +import 'package:flutter/material.dart'; +import 'package:mobile_scanner/mobile_scanner.dart'; + +class QRScanner extends StatelessWidget { + const QRScanner({super.key}); + + @override + Widget build(BuildContext context) { + return MobileScanner( + onDetect: (result) { + Navigator.pop(context, result); + }, + ); + } + +} \ No newline at end of file diff --git a/lib/pages/registerpage.dart b/lib/pages/registerpage.dart index df835a2..e91c7c2 100644 --- a/lib/pages/registerpage.dart +++ b/lib/pages/registerpage.dart @@ -4,7 +4,6 @@ import 'package:flutter/material.dart'; import 'package:liteauthconfig/models/appconfig.dart'; import 'package:liteauthconfig/dialogs/esptouchdialog.dart'; import 'package:liteauthconfig/l10n/app_localizations.dart'; -import 'package:multicast_dns/multicast_dns.dart'; import 'package:network_info_plus/network_info_plus.dart'; import 'package:permission_handler/permission_handler.dart'; @@ -44,7 +43,7 @@ class _RegisterPageState extends State { var appLocal = AppLocalizations.of(context)!; var appTheme = Theme.of(context); - if (await Permission.location.isDenied) { + if ((Platform.isAndroid || Platform.isIOS) && await Permission.location.isDenied) { showDialog( context: context, builder: (context) => AlertDialog.adaptive( @@ -70,7 +69,7 @@ class _RegisterPageState extends State { ], ), ); - } else if (await Permission.location.isGranted) { + } else if (!(Platform.isAndroid || Platform.isIOS) || await Permission.location.isGranted) { fetchNetworkInfo(); } } @@ -95,12 +94,29 @@ class _RegisterPageState extends State { } void submit() async { + var appLocal = AppLocalizations.of(context)!; + var name = nameController.text.isEmpty ? ssidController.text : nameController.text; + + if (ssidController.text.isEmpty) { + ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text( + appLocal.cannotBeEmpty("SSID") + ),)); + return; + } + + if (bssidController.text.isEmpty) { + ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text( + appLocal.cannotBeEmpty("BSSID") + ),)); + return; + } + if (widget.setup) { await showDialog( context: context, barrierDismissible: false, builder: (context) => ESPTouchDialog( - name: nameController.text, + name: name, ssid: ssidController.text, bssid: bssidController.text, password: passwordController.text, @@ -109,26 +125,12 @@ class _RegisterPageState extends State { ); } else { final dev = Device( - name: nameController.text, + name: name, routerSsid: ssidController.text, routerBssid: bssidController.text, networkPassword: passwordController.text, ); - final MDnsClient client = MDnsClient(); - await client.start(); - - // TODO: Change to dynamic mDNS name - String name = "liteauth.local"; - - await for (final PtrResourceRecord ptr - in client.lookup( - ResourceRecordQuery.serverPointer(name), - )) { - await for (final SrvResourceRecord srv in client.lookup(ResourceRecordQuery.service(ptr.domainName))) { - // TODO: Actually implement record lookup - } - } AppConfig().devices.add(dev); } if (context.mounted) { diff --git a/lib/pages/tokeninfo.dart b/lib/pages/tokeninfo.dart new file mode 100644 index 0000000..922fba1 --- /dev/null +++ b/lib/pages/tokeninfo.dart @@ -0,0 +1,163 @@ +import 'dart:io'; + +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:gap/gap.dart'; +import 'package:liteauthconfig/l10n/app_localizations.dart'; +import 'package:liteauthconfig/models/appconfig.dart'; +import 'package:liteauthconfig/pages/qrscanner.dart'; +import 'package:mobile_scanner/mobile_scanner.dart'; +import 'package:qr_flutter/qr_flutter.dart'; + +class TokenInfo extends StatefulWidget { + final int deviceIndex; + final String token; + + const TokenInfo(this.deviceIndex, this.token, {super.key}); + + @override + State createState() => _TokenInfoState(); +} + +class _TokenInfoState extends State { + TextEditingController tokenController = TextEditingController(); + bool showToken = false; + + @override + void initState() { + tokenController.text = widget.token; + super.initState(); + } + + Future saveToken() async { + final appLocal = AppLocalizations.of(context)!; + var config = AppConfig(); + + config.devices[widget.deviceIndex].token = + tokenController.text; + await config.save(); + + if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text(appLocal.saved)), + ); + } + } + + Future scanQrCode() async { + var code = await Navigator.push( + context, + MaterialPageRoute(builder: (ctx) => QRScanner()), + ); + var value = code?.barcodes.first.rawValue; + + if (code == null || value == null) return; + + tokenController.text = value; + await saveToken(); + } + + @override + Widget build(BuildContext context) { + final appLocal = AppLocalizations.of(context)!; + + return Scaffold( + appBar: AppBar(title: Text(appLocal.token)), + body: SingleChildScrollView( + child: Padding( + padding: EdgeInsetsGeometry.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(appLocal.viewTokenWarn), + + Row( + children: [ + Checkbox.adaptive( + semanticLabel: appLocal.showToken, + value: showToken, + onChanged: (newValue) { + setState(() { + showToken = newValue!; + }); + }, + ), + Text(appLocal.showToken), + ], + ), + + Visibility( + visible: showToken, + child: Center( + child: Column( + children: [ + Visibility( + visible: tokenController.text.isNotEmpty, + replacement: Text(appLocal.tokenNotFound), + child: Column( + children: [ + SizedBox.square( + dimension: 200, + child: QrImageView( + data: tokenController.text, + backgroundColor: Colors.white, + padding: EdgeInsets.all(16), + ), + ), + Gap(16), + OutlinedButton( + onPressed: () async { + await Clipboard.setData( + ClipboardData(text: tokenController.text), + ); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text(appLocal.copied)), + ); + }, + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + const Icon(Icons.copy), + Gap(8), + Text(appLocal.copyToken), + ], + ), + ), + ], + ), + ), + Gap(16), + TextField( + controller: tokenController, + decoration: InputDecoration( + border: OutlineInputBorder(), + labelText: appLocal.token, + suffixIcon: IconButton( + onPressed: Platform.isLinux || Platform.isWindows + ? null + : scanQrCode, + icon: const Icon(Icons.qr_code_scanner), + ), + ), + onChanged: (newValue) { + setState(() {}); + }, + ), + Gap(16), + FilledButton( + onPressed: tokenController.text == widget.token + ? null + : saveToken, + child: Text(appLocal.saveToken), + ), + ], + ), + ), + ), + ], + ), + ), + ), + ); + } +} diff --git a/lib/utils/network.dart b/lib/utils/network.dart index 3e1ce2b..2a01424 100644 --- a/lib/utils/network.dart +++ b/lib/utils/network.dart @@ -1,17 +1,32 @@ import 'dart:io'; +import 'package:dio/dio.dart'; +import 'package:dio/io.dart'; import 'package:flutter/services.dart'; -import 'package:http/http.dart' as http; -import 'package:http/io_client.dart'; -Future createEspHttpClient() async { +Future createEspHttpClient({String token = ""}) async { + Dio dio = Dio(); + final certData = await rootBundle.load("assets/certificates/rootCA.crt"); final certBytes = certData.buffer.asUint8List(); - SecurityContext securityContext = SecurityContext.defaultContext; - securityContext.setTrustedCertificatesBytes(certBytes); + dio.httpClientAdapter = IOHttpClientAdapter( + createHttpClient: () { + SecurityContext securityContext = SecurityContext.defaultContext; + securityContext.setTrustedCertificatesBytes(certBytes); - HttpClient client = HttpClient(context: securityContext); + return HttpClient(context: securityContext); + } + ); - return IOClient(client); + if (token.isNotEmpty) { + dio.interceptors.add(InterceptorsWrapper(onRequest: (RequestOptions options, RequestInterceptorHandler handler) { + options.headers.addAll({ + "Authorization": "Bearer $token" + }); + return handler.next(options); + })); + } + + return dio; } \ No newline at end of file diff --git a/linux/CMakeLists.txt b/linux/CMakeLists.txt index f75d142..d7aea84 100644 --- a/linux/CMakeLists.txt +++ b/linux/CMakeLists.txt @@ -7,7 +7,7 @@ project(runner LANGUAGES CXX) set(BINARY_NAME "liteauthconfig") # The unique GTK application identifier for this application. See: # https://wiki.gnome.org/HowDoI/ChooseApplicationID -set(APPLICATION_ID "xyz.dailitation.linesofcodes.liteauthconfig.liteauthconfig") +set(APPLICATION_ID "xyz.dailitation.linesofcodes.liteauthconfig") # 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 1112ba9..5c3d497 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -6,11 +6,13 @@ import FlutterMacOS import Foundation import flutter_secure_storage_darwin +import mobile_scanner import network_info_plus import system_theme func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { FlutterSecureStorageDarwinPlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStorageDarwinPlugin")) + MobileScannerPlugin.register(with: registry.registrar(forPlugin: "MobileScannerPlugin")) NetworkInfoPlusPlugin.register(with: registry.registrar(forPlugin: "NetworkInfoPlusPlugin")) SystemThemePlugin.register(with: registry.registrar(forPlugin: "SystemThemePlugin")) } diff --git a/macos/Runner.xcodeproj/project.pbxproj b/macos/Runner.xcodeproj/project.pbxproj index e3dd5e5..3d6b461 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 = xyz.dailitation.linesofcodes.liteauthconfig.liteauthconfig.RunnerTests; + PRODUCT_BUNDLE_IDENTIFIER = xyz.dailitation.linesofcodes.liteauthconfig.RunnerTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/liteauthconfig.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/liteauthconfig"; @@ -399,7 +399,7 @@ CURRENT_PROJECT_VERSION = 1; GENERATE_INFOPLIST_FILE = YES; MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = xyz.dailitation.linesofcodes.liteauthconfig.liteauthconfig.RunnerTests; + PRODUCT_BUNDLE_IDENTIFIER = xyz.dailitation.linesofcodes.liteauthconfig.RunnerTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/liteauthconfig.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/liteauthconfig"; @@ -413,7 +413,7 @@ CURRENT_PROJECT_VERSION = 1; GENERATE_INFOPLIST_FILE = YES; MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = xyz.dailitation.linesofcodes.liteauthconfig.liteauthconfig.RunnerTests; + PRODUCT_BUNDLE_IDENTIFIER = xyz.dailitation.linesofcodes.liteauthconfig.RunnerTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/liteauthconfig.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/liteauthconfig"; diff --git a/macos/Runner/Configs/AppInfo.xcconfig b/macos/Runner/Configs/AppInfo.xcconfig index c8236d1..de61a48 100644 --- a/macos/Runner/Configs/AppInfo.xcconfig +++ b/macos/Runner/Configs/AppInfo.xcconfig @@ -8,7 +8,7 @@ PRODUCT_NAME = liteauthconfig // The application's bundle identifier -PRODUCT_BUNDLE_IDENTIFIER = xyz.dailitation.linesofcodes.liteauthconfig.liteauthconfig +PRODUCT_BUNDLE_IDENTIFIER = xyz.dailitation.linesofcodes.liteauthconfig // The copyright displayed in application information PRODUCT_COPYRIGHT = Copyright © 2025 xyz.dailitation.linesofcodes.liteauthconfig. All rights reserved. diff --git a/pubspec.lock b/pubspec.lock index 9401ed7..3a4d73a 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -177,6 +177,22 @@ packages: url: "https://pub.dev" source: hosted version: "0.7.11" + dio: + dependency: "direct main" + description: + name: dio + sha256: b9d46faecab38fc8cc286f80bc4d61a3bb5d4ac49e51ed877b4d6706efe57b25 + url: "https://pub.dev" + source: hosted + version: "5.9.1" + dio_web_adapter: + dependency: transitive + description: + name: dio_web_adapter + sha256: "7586e476d70caecaf1686d21eee7247ea43ef5c345eab9e0cc3583ff13378d78" + url: "https://pub.dev" + source: hosted + version: "2.1.1" esptouch_flutter: dependency: "direct main" description: @@ -302,6 +318,14 @@ packages: description: flutter source: sdk version: "0.0.0" + gap: + dependency: "direct main" + description: + name: gap + sha256: f19387d4e32f849394758b91377f9153a1b41d79513ef7668c088c77dbc6955d + url: "https://pub.dev" + source: hosted + version: "3.0.1" glob: dependency: transitive description: @@ -426,10 +450,10 @@ packages: dependency: transitive description: name: lints - sha256: a5e2b223cb7c9c8efdc663ef484fdd95bb243bff242ef5b13e26883547fce9a0 + sha256: "12f842a479589fea194fe5c5a3095abc7be0c1f2ddfa9a0e76aed1dbd26a87df" url: "https://pub.dev" source: hosted - version: "6.0.0" + version: "6.1.0" logging: dependency: transitive description: @@ -470,14 +494,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.0" - multicast_dns: + mobile_scanner: dependency: "direct main" description: - name: multicast_dns - sha256: de72ada5c3db6fdd6ad4ae99452fe05fb403c4bb37c67ceb255ddd37d2b5b1eb + name: mobile_scanner + sha256: c6184bf2913dd66be244108c9c27ca04b01caf726321c44b0e7a7a1e32d41044 url: "https://pub.dev" source: hosted - version: "0.3.3" + version: "7.1.4" native_toolchain_c: dependency: transitive description: @@ -702,6 +726,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.5.0" + qr: + dependency: transitive + description: + name: qr + sha256: "5a1d2586170e172b8a8c8470bbbffd5eb0cd38a66c0d77155ea138d3af3a4445" + url: "https://pub.dev" + source: hosted + version: "3.0.2" + qr_flutter: + dependency: "direct main" + description: + name: qr_flutter + sha256: "5095f0fc6e3f71d08adef8feccc8cea4f12eec18a2e31c2e8d82cb6019f4b097" + url: "https://pub.dev" + source: hosted + version: "4.1.0" quiver: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 281d2c6..bb22a7a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -51,10 +51,13 @@ dependencies: path: ^1.9.1 json_annotation: ^4.10.0 flutter_speed_dial: ^7.0.0 - multicast_dns: ^0.3.3 http: ^1.6.0 nfc_manager: ^4.1.1 nfc_manager_ndef: ^1.1.0 + qr_flutter: ^4.1.0 + dio: ^5.9.1 + gap: ^3.0.1 + mobile_scanner: ^7.1.4 dev_dependencies: flutter_test: