diff --git a/README.md b/README.md index da8eaf2..cfbddfb 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ - + -# ReCon +# recon A Resonite Contacts App -[Get it here](https://github.com/Nutcake/ReCon/releases/latest) +[Get it here](https://github.com/Nutcake/recon/releases/latest) ## Building @@ -17,4 +17,4 @@ For example, notifications are currently not supported on non-android builds. ## Screenshots - + diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index e16b842..bd0fde5 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -7,7 +7,7 @@ @@ -31,7 +31,7 @@ @@ -65,7 +65,7 @@ @@ -82,7 +82,7 @@ @@ -93,7 +93,7 @@ diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index 2ca4313..997e8dc 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -7,7 +7,7 @@ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleDisplayName - ReCon + recon CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier @@ -15,7 +15,7 @@ CFBundleInfoDictionaryVersion 6.0 CFBundleName - ReCon + recon CFBundlePackageType APPL CFBundleShortVersionString diff --git a/lib/apis/github_api.dart b/lib/apis/github_api.dart index 0452f1a..4da578c 100644 --- a/lib/apis/github_api.dart +++ b/lib/apis/github_api.dart @@ -6,7 +6,7 @@ class GithubApi { static const baseUrl = "https://api.github.com"; static Future getLatestTagName() async { - final response = await http.get(Uri.parse("$baseUrl/repos/Nutcake/ReCon/releases?per_page=1")); + final response = await http.get(Uri.parse("$baseUrl/repos/Nutcake/recon/releases?per_page=1")); if (response.statusCode != 200) return ""; final body = jsonDecode(response.body) as List; if (body.isEmpty) return ""; diff --git a/lib/clients/messaging_client.dart b/lib/clients/messaging_client.dart index 37de60f..59c97f2 100644 --- a/lib/clients/messaging_client.dart +++ b/lib/clients/messaging_client.dart @@ -228,17 +228,19 @@ class MessagingClient extends ChangeNotifier { // Adjusting values to ensure correct placement of 'headless' if (friend.isHeadless) return 2.5; switch (friend.userStatus.onlineStatus) { - case OnlineStatus.online: + case OnlineStatus.sociable: return 0; - case OnlineStatus.away: + case OnlineStatus.online: return 1; - case OnlineStatus.busy: + case OnlineStatus.away: return 2; + case OnlineStatus.busy: + return 3; case OnlineStatus.invisible: - return 2.5; + return 3.5; case OnlineStatus.offline: default: - return 3; + return 4; } } diff --git a/lib/clients/notification_client.dart b/lib/clients/notification_client.dart index 812cdde..999ddf6 100644 --- a/lib/clients/notification_client.dart +++ b/lib/clients/notification_client.dart @@ -26,7 +26,7 @@ class NotificationClient { android: fln.AndroidInitializationSettings("ic_notification"), iOS: fln.DarwinInitializationSettings(), macOS: fln.DarwinInitializationSettings(), - linux: fln.LinuxInitializationSettings(defaultActionName: "Open ReCon"), + linux: fln.LinuxInitializationSettings(defaultActionName: "Open recon"), )); Future showUnreadMessagesNotification(Iterable messages) async { diff --git a/lib/main.dart b/lib/main.dart index 897c1a2..3e84ffb 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -59,20 +59,20 @@ void main() async { // Ignore } - runApp(ReCon(settingsClient: settingsClient, cachedAuthentication: cachedAuth)); + runApp(recon(settingsClient: settingsClient, cachedAuthentication: cachedAuth)); } -class ReCon extends StatefulWidget { - const ReCon({required this.settingsClient, required this.cachedAuthentication, super.key}); +class recon extends StatefulWidget { + const recon({required this.settingsClient, required this.cachedAuthentication, super.key}); final SettingsClient settingsClient; final AuthenticationData cachedAuthentication; @override - State createState() => _ReConState(); + State createState() => _reconState(); } -class _ReConState extends State { +class _reconState extends State { final Typography _typography = Typography.material2021(platform: defaultTargetPlatform); final ReceivePort _port = ReceivePort(); late AuthenticationData _authData = widget.cachedAuthentication; @@ -165,7 +165,7 @@ class _ReConState extends State { child: DynamicColorBuilder( builder: (ColorScheme? lightDynamic, ColorScheme? darkDynamic) => MaterialApp( debugShowCheckedModeBanner: true, - title: 'ReCon', + title: 'recon', theme: ThemeData( useMaterial3: true, textTheme: _typography.black, diff --git a/lib/models/users/online_status.dart b/lib/models/users/online_status.dart index 2d8d8bf..d02edd4 100644 --- a/lib/models/users/online_status.dart +++ b/lib/models/users/online_status.dart @@ -5,14 +5,16 @@ enum OnlineStatus { invisible, away, busy, - online; + online, + sociable; static final List _colors = [ Colors.transparent, - Colors.transparent, + Colors.grey, Colors.yellow, Colors.red, Colors.green, + Colors.blue, ]; Color color(BuildContext context) => this == OnlineStatus.offline || this == OnlineStatus.invisible @@ -28,6 +30,8 @@ enum OnlineStatus { int compareTo(OnlineStatus other) { if (this == other) return 0; + if (this == OnlineStatus.sociable) return -1; + if (other == OnlineStatus.sociable) return 1; if (this == OnlineStatus.online) return -1; if (other == OnlineStatus.online) return 1; if (this == OnlineStatus.away) return -1; diff --git a/lib/widgets/friends/friend_online_status_indicator.dart b/lib/widgets/friends/friend_online_status_indicator.dart index 65e4d58..48e13e1 100644 --- a/lib/widgets/friends/friend_online_status_indicator.dart +++ b/lib/widgets/friends/friend_online_status_indicator.dart @@ -12,7 +12,7 @@ class FriendOnlineStatusIndicator extends StatelessWidget { Widget build(BuildContext context) { final UserStatus userStatus = friend.userStatus; final OnlineStatus onlineStatus = userStatus.onlineStatus; - return userStatus.appVersion.contains("ReCon") && friend.isOnline + return userStatus.appVersion.contains("recon") && friend.isOnline ? SizedBox.square( dimension: 10, child: Image.asset( diff --git a/lib/widgets/friends/friends_list_app_bar.dart b/lib/widgets/friends/friends_list_app_bar.dart index fbee120..218c27c 100644 --- a/lib/widgets/friends/friends_list_app_bar.dart +++ b/lib/widgets/friends/friends_list_app_bar.dart @@ -21,7 +21,7 @@ class _FriendsListAppBarState extends State with AutomaticKee Widget build(BuildContext context) { super.build(context); return AppBar( - title: const Text("ReCon"), + title: const Text("recon"), actions: [ Consumer(builder: (context, client, _) { return PopupMenuButton( diff --git a/lib/widgets/login_screen.dart b/lib/widgets/login_screen.dart index 6b38e48..09b370d 100644 --- a/lib/widgets/login_screen.dart +++ b/lib/widgets/login_screen.dart @@ -55,13 +55,8 @@ class _LoginScreenState extends State { ); Future submit() async { - if (_usernameController.text.contains(emailReg) || _passwordController.text.isEmpty) { - setState(() { - _error = "Email found! YAAAAY!"; - _isUsernameEmail = true; - }); - } - if (_usernameController.text.isEmpty ||_usernameController.text.contains(emailReg) || _passwordController.text.isEmpty) { //some little thing is giving me the hiccups + + if (_usernameController.text.isEmpty || _passwordController.text.isEmpty) { setState(() { _error = "Please enter a valid username/password combination."; }); @@ -116,7 +111,62 @@ class _LoginScreenState extends State { }); } } - + Future passwordResetSubmit() async { + if (_usernameController.text.contains(emailReg) || _passwordController.text.isEmpty) { + setState(() { + _error = "Please provide an email on the 'Username' textbox"; + }); + return; + } + setState(() { + _error = ""; + _isLoading = false; + }); + /*try { + final authData = await ApiClient.tryLogin( + username: _usernameController.text, + password: _passwordController.text, + oneTimePad: _totpController.text.isEmpty ? null : _totpController.text, + ); + if (!authData.isAuthenticated) { + setState(() { + _error = "Login unsuccessful: Server sent invalid response."; + _isLoading = false; + }); + return; + } + setState(() { + _error = ""; + _isLoading = false; + }); + await loginSuccessful(authData); + } catch (e, s) { + setState(() { + if (e == ApiClient.totpKey) { + if (_needsTotp == false) { + _error = "Please enter your 2FA-Code"; + _totpFocusNode.requestFocus(); + WidgetsBinding.instance.addPostFrameCallback((timeStamp) { + _scrollController.animateTo(_scrollController.position.maxScrollExtent, + duration: const Duration(milliseconds: 400), curve: Curves.easeOutCirc); + }); + } else { + _error = "The given 2FA code is not valid."; + } + _needsTotp = true; + } else { + _error = "Login unsuccessful: $e."; + } + if (kDebugMode) { + FlutterError.reportError(FlutterErrorDetails( + exception: e, + stack: s, + )); + } + _isLoading = false; + }); + }*/ + } Future loginSuccessful(AuthenticationData authData) async { final settingsClient = ClientHolder.of(context).settingsClient; final notificationManager = FlutterLocalNotificationsPlugin(); @@ -173,7 +223,7 @@ class _LoginScreenState extends State { Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: const Text("OpenContacts"), + title: const Text("recon"), ), body: Builder(builder: (context) { return ListView( @@ -240,13 +290,13 @@ class _LoginScreenState extends State { label: const Text("Login"), ), ), - Padding( + Padding( padding: const EdgeInsets.only(top: 16), - child: _isLoading + child: _isUsernameEmail ? const Center(child: CircularProgressIndicator()) : TextButton.icon( - onPressed: submit, - icon: const Icon(Icons.question_mark), + onPressed: passwordResetSubmit, + icon: const Icon(Icons.refresh), label: const Text("Forgot Password?"), ), ), diff --git a/lib/widgets/settings_page.dart b/lib/widgets/settings_page.dart index fc50aaf..b16b940 100644 --- a/lib/widgets/settings_page.dart +++ b/lib/widgets/settings_page.dart @@ -74,14 +74,14 @@ class SettingsPage extends StatelessWidget { ), ListTile( trailing: const Icon(Icons.info_outline), - title: const Text("About ReCon"), + title: const Text("About recon"), onTap: () async { showAboutDialog( context: context, applicationVersion: (await PackageInfo.fromPlatform()).version, applicationIcon: InkWell( onTap: () async { - if (!await launchUrl(Uri.parse("https://github.com/Nutcake/ReCon"), + if (!await launchUrl(Uri.parse("https://github.com/Nutcake/recon"), mode: LaunchMode.externalApplication)) { if (context.mounted) { ScaffoldMessenger.of(context) diff --git a/lib/widgets/update_notifier.dart b/lib/widgets/update_notifier.dart index 4fe903a..415cec7 100644 --- a/lib/widgets/update_notifier.dart +++ b/lib/widgets/update_notifier.dart @@ -38,7 +38,7 @@ class UpdateNotifier extends StatelessWidget { children: [ TextButton.icon( onPressed: () { - launchUrl(Uri.parse("https://github.com/Nutcake/ReCon/releases/latest"), + launchUrl(Uri.parse("https://github.com/Nutcake/recon/releases/latest"), mode: LaunchMode.externalApplication, ); }, diff --git a/linux/my_application.cc b/linux/my_application.cc index 26ee844..dbd4e93 100644 --- a/linux/my_application.cc +++ b/linux/my_application.cc @@ -40,11 +40,11 @@ static void my_application_activate(GApplication* application) { if (use_header_bar) { GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); gtk_widget_show(GTK_WIDGET(header_bar)); - gtk_header_bar_set_title(header_bar, "ReCon"); + gtk_header_bar_set_title(header_bar, "recon"); gtk_header_bar_set_show_close_button(header_bar, TRUE); gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); } else { - gtk_window_set_title(window, "ReCon"); + gtk_window_set_title(window, "recon"); } gtk_window_set_default_size(window, 480, 900); diff --git a/macos/Runner.xcodeproj/project.pbxproj b/macos/Runner.xcodeproj/project.pbxproj index 4bc5c96..578036b 100644 --- a/macos/Runner.xcodeproj/project.pbxproj +++ b/macos/Runner.xcodeproj/project.pbxproj @@ -54,7 +54,7 @@ 331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; - 33CC10ED2044A3C60003C045 /* ReCon.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ReCon.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 33CC10ED2044A3C60003C045 /* recon.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = recon.app; sourceTree = BUILT_PRODUCTS_DIR; }; 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; @@ -134,7 +134,7 @@ 33CC10EE2044A3C60003C045 /* Products */ = { isa = PBXGroup; children = ( - 33CC10ED2044A3C60003C045 /* ReCon.app */, + 33CC10ED2044A3C60003C045 /* recon.app */, 331C80D5294CF71000263BE5 /* RunnerTests.xctest */, ); name = Products; @@ -238,7 +238,7 @@ ); name = Runner; productName = Runner; - productReference = 33CC10ED2044A3C60003C045 /* ReCon.app */; + productReference = 33CC10ED2044A3C60003C045 /* recon.app */; productType = "com.apple.product-type.application"; }; /* End PBXNativeTarget section */ @@ -570,7 +570,7 @@ DEVELOPMENT_TEAM = P9AV4LPNLL; FLUTTER_BUILD_NAME = "0.11.1-beta"; INFOPLIST_FILE = Runner/Info.plist; - INFOPLIST_KEY_CFBundleDisplayName = ReCon; + INFOPLIST_KEY_CFBundleDisplayName = recon; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -578,7 +578,7 @@ ); MARKETING_VERSION = "0.11.1-beta"; PRODUCT_BUNDLE_IDENTIFIER = ch.isota.recon; - PRODUCT_NAME = ReCon; + PRODUCT_NAME = recon; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_VERSION = 5.0; }; @@ -710,7 +710,7 @@ DEVELOPMENT_TEAM = P9AV4LPNLL; FLUTTER_BUILD_NAME = "0.11.1-beta"; INFOPLIST_FILE = Runner/Info.plist; - INFOPLIST_KEY_CFBundleDisplayName = ReCon; + INFOPLIST_KEY_CFBundleDisplayName = recon; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -718,7 +718,7 @@ ); MARKETING_VERSION = "0.11.1-beta"; PRODUCT_BUNDLE_IDENTIFIER = ch.isota.recon; - PRODUCT_NAME = ReCon; + PRODUCT_NAME = recon; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; @@ -741,7 +741,7 @@ DEVELOPMENT_TEAM = P9AV4LPNLL; FLUTTER_BUILD_NAME = "0.11.1-beta"; INFOPLIST_FILE = Runner/Info.plist; - INFOPLIST_KEY_CFBundleDisplayName = ReCon; + INFOPLIST_KEY_CFBundleDisplayName = recon; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -749,7 +749,7 @@ ); MARKETING_VERSION = "0.11.1-beta"; PRODUCT_BUNDLE_IDENTIFIER = ch.isota.recon; - PRODUCT_NAME = ReCon; + PRODUCT_NAME = recon; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_VERSION = 5.0; }; diff --git a/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index 1c305fd..00df61e 100644 --- a/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -15,7 +15,7 @@ @@ -31,7 +31,7 @@ @@ -65,7 +65,7 @@ @@ -82,7 +82,7 @@ diff --git a/pubspec.yaml b/pubspec.yaml index 7fc7ea6..d01ac17 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,4 +1,4 @@ -name: recon +name: OpenContacts description: A Resonite Contacts App for Android # The following line prevents the package from being accidentally published to # pub.dev using `flutter pub publish`. This is preferred for private packages. @@ -16,7 +16,7 @@ publish_to: "none" # Remove this line if you wish to publish to pub.dev # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # In Windows, build-name is used as the major, minor, and patch parts # of the product and file versions while build-number is used as the build suffix. -version: 0.11.3-beta+1 +version: 0.1.0-indev+1 environment: sdk: ">=3.0.1" diff --git a/test/widget_test.dart b/test/widget_test.dart index 59c6120..5462ad9 100644 --- a/test/widget_test.dart +++ b/test/widget_test.dart @@ -14,7 +14,7 @@ import 'package:recon/models/authentication_data.dart'; void main() { testWidgets('Counter increments smoke test', (WidgetTester tester) async { // Build our app and trigger a frame. - await tester.pumpWidget(ReCon( + await tester.pumpWidget(recon( settingsClient: SettingsClient(), cachedAuthentication: AuthenticationData.unauthenticated(), ));