diff --git a/.woodpecker/workflow.yaml b/.woodpecker/workflow.yaml new file mode 100644 index 0000000..088760e --- /dev/null +++ b/.woodpecker/workflow.yaml @@ -0,0 +1,15 @@ +when: + - event: push + branch: dev + +steps: + - name: build + image: instrumentisto/flutter + commands: + - cd OpenContacts + - echo "Starting to build..." + - flutter build --debug + - name: Deploy + image: debian + commands: + - echo "Hello World" \ No newline at end of file diff --git a/README.md b/README.md index 594b1d8..42c9798 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ - + ## OpenContacts diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 363d486..5f9ed7a 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -9,7 +9,7 @@ + android:icon="@mipmap/launcher_icon"> with AutomaticKee Widget build(BuildContext context) { super.build(context); return AppBar( - title: const Text("OpenContacts"), + title: const Text("Contacts"), actions: [ Consumer(builder: (context, client, _) { return PopupMenuButton( @@ -84,7 +84,7 @@ class _FriendsListAppBarState extends State with AutomaticKee await itemDef.onTap(); }, itemBuilder: (BuildContext context) => [ - MenuItemDefinition( + /*MenuItemDefinition( name: "Add Users", icon: Icons.person_add, onTap: () async { @@ -98,7 +98,8 @@ class _FriendsListAppBarState extends State with AutomaticKee ), ); }, - ), + ),*/ + //TODO: Add users API MenuItemDefinition( name: "My Profile", icon: Icons.person, diff --git a/lib/widgets/friends/user_list_tile.dart b/lib/widgets/friends/user_list_tile.dart index 2e4f881..cad769a 100644 --- a/lib/widgets/friends/user_list_tile.dart +++ b/lib/widgets/friends/user_list_tile.dart @@ -28,13 +28,13 @@ class _UserListTileState extends State { .of(context) .colorScheme; final style = _localAdded ? IconButton.styleFrom( - foregroundColor: colorScheme.onBackground, + foregroundColor: colorScheme.onSurface, side: BorderSide( color: colorScheme.error, width: 2 ), ) : IconButton.styleFrom( - foregroundColor: colorScheme.onBackground, + foregroundColor: colorScheme.onSurface, side: BorderSide( color: colorScheme.primary, width: 2 @@ -50,7 +50,7 @@ class _UserListTileState extends State { icon: _localAdded ? const Icon(Icons.person_remove) : const Icon(Icons.person_add), style: style, onPressed: _loading ? null : () async { - ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text("Sorry, this feature is not yet available"))); + ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text("Sorry, this feature is unavailable."))); return; setState(() { _loading = true; diff --git a/lib/widgets/homepage.dart b/lib/widgets/homepage.dart index 81420cd..4d900d2 100644 --- a/lib/widgets/homepage.dart +++ b/lib/widgets/homepage.dart @@ -65,8 +65,8 @@ class _HomeState extends State { label: "Sessions", ), NavigationDestination( - icon: Icon(Icons.message), - label: "Chat", + icon: Icon(Icons.contacts), + label: "Contacts", ), NavigationDestination( icon: Icon(Icons.inventory), diff --git a/lib/widgets/inventory/inventory_browser.dart b/lib/widgets/inventory/inventory_browser.dart index cf05849..13c1bbb 100644 --- a/lib/widgets/inventory/inventory_browser.dart +++ b/lib/widgets/inventory/inventory_browser.dart @@ -192,12 +192,18 @@ class _InventoryBrowserState extends State with AutomaticKeepA : () async { await Navigator.push( context, - MaterialPageRoute( - builder: (context) => PhotoView( - minScale: PhotoViewComputedScale.contained, - imageProvider: - CachedNetworkImageProvider(Aux.resdbToHttp(record.thumbnailUri)), - heroAttributes: PhotoViewHeroAttributes(tag: record.id), + MaterialPageRoute( + builder: (context) => Scaffold( + appBar: AppBar( + title: Text(record.formattedName.toString()), + ), + body: Center ( + child: CachedNetworkImage( + imageUrl: (Aux.resdbToHttp(record.thumbnailUri)), + placeholder: (context, url) => const CircularProgressIndicator(), + errorWidget: (context, url, error) => const Icon(Icons.error), + ), + ), ), ), ); diff --git a/lib/widgets/login_screen.dart b/lib/widgets/login_screen.dart index d6fbd3a..621312a 100644 --- a/lib/widgets/login_screen.dart +++ b/lib/widgets/login_screen.dart @@ -27,7 +27,6 @@ class _LoginScreenState extends State { late final FocusNode _totpFocusNode; bool _isLoading = false; - bool _isEmailResetSend = false; String _error = ""; bool _needsTotp = false; @@ -47,13 +46,6 @@ class _LoginScreenState extends State { _totpFocusNode.dispose(); super.dispose(); } - RegExp emailReg = RegExp( - r"^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$", - - caseSensitive: false, - multiLine: false, - - ); Future submit() async { if (_usernameController.text.isEmpty || _passwordController.text.isEmpty) { @@ -111,69 +103,7 @@ class _LoginScreenState extends State { }); } } - Future passwordResetSubmit() async { - if (_usernameController.text.isEmpty) { - setState(() { - _error = "Please provide an email on the 'Username' textbox"; - }); - return; - } - if (_usernameController.text.contains(emailReg)) { - setState(() { - _error = "An email to reset your password has been requested to resonite."; - _isEmailResetSend = true; - }); - return; - } - setState(() { - _error = ""; - _isEmailResetSend = true; - }); - /*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(); @@ -297,16 +227,6 @@ class _LoginScreenState extends State { label: const Text("Login"), ), ), - /*Padding( - padding: const EdgeInsets.only(top: 16), - child: _isEmailResetSend - ? const Center(child: CircularProgressIndicator()) - : TextButton.icon( - onPressed: passwordResetSubmit, - icon: const Icon(Icons.refresh), - label: const Text("Forgot Password?"), - ), - ),*/ // I have to look into this feature and understand how password resseting works Center( child: AnimatedOpacity( opacity: _errorOpacity, diff --git a/lib/widgets/my_profile_dialog.dart b/lib/widgets/my_profile_dialog.dart index db19418..9d79318 100644 --- a/lib/widgets/my_profile_dialog.dart +++ b/lib/widgets/my_profile_dialog.dart @@ -6,6 +6,7 @@ import 'package:OpenContacts/client_holder.dart'; import 'package:OpenContacts/models/personal_profile.dart'; import 'package:OpenContacts/widgets/default_error_widget.dart'; import 'package:OpenContacts/widgets/generic_avatar.dart'; +import 'package:OpenContacts/models/users/friend.dart'; class MyProfileDialog extends StatefulWidget { const MyProfileDialog({super.key}); @@ -30,7 +31,7 @@ class _MyProfileDialogState extends State { _storageQuotaFuture = UserApi.getStorageQuota(apiClient); } } - + @override Widget build(BuildContext context) { final tt = Theme.of(context).textTheme; diff --git a/lib/widgets/sessions/session_list.dart b/lib/widgets/sessions/session_list.dart index f4a6c1c..7759b30 100644 --- a/lib/widgets/sessions/session_list.dart +++ b/lib/widgets/sessions/session_list.dart @@ -7,6 +7,7 @@ import 'package:OpenContacts/widgets/formatted_text.dart'; import 'package:OpenContacts/widgets/sessions/session_view.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; +import 'package:flutter/services.dart'; class SessionList extends StatefulWidget { const SessionList({super.key}); @@ -14,6 +15,11 @@ class SessionList extends StatefulWidget { @override State createState() => _SessionListState(); } +class onKeyIntent extends Intent{ + const onKeyIntent(); +} + +const onKey = SingleActivator(LogicalKeyboardKey.f5); class _SessionListState extends State with AutomaticKeepAliveClientMixin { @override @@ -53,7 +59,7 @@ class _SessionListState extends State with AutomaticKeepAliveClient ? const DefaultErrorWidget( title: "No Sessions Found", message: "Try to adjust your filters", - iconOverride: Icons.public_off, + iconOverride: Icons.question_mark, ) : Padding( padding: const EdgeInsets.symmetric(horizontal: 8.0), @@ -63,7 +69,7 @@ class _SessionListState extends State with AutomaticKeepAliveClient gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent( maxCrossAxisExtent: 256, crossAxisSpacing: 4, - mainAxisSpacing: 4, + mainAxisSpacing: 1, childAspectRatio: .8, ), itemBuilder: (context, index) { @@ -126,7 +132,24 @@ class _SessionListState extends State with AutomaticKeepAliveClient ], ), const SizedBox( - height: 4, + height: 2, + ), + Row( + children: [ + Expanded( + child: Text( + "Host: ${session.hostUsername}", + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: Theme.of(context).textTheme.bodyMedium?.copyWith( + color: Color.fromARGB(234, 151, 107, 61) + ), + ), + ), + ], + ), + const SizedBox( + height: 2, ), Row( children: [ diff --git a/lib/widgets/sessions/session_view.dart b/lib/widgets/sessions/session_view.dart index 8f20525..b6a9eae 100644 --- a/lib/widgets/sessions/session_view.dart +++ b/lib/widgets/sessions/session_view.dart @@ -1,3 +1,4 @@ +import 'package:OpenContacts/models/users/user.dart'; import 'package:cached_network_image/cached_network_image.dart'; import 'package:OpenContacts/apis/session_api.dart'; import 'package:OpenContacts/auxiliary.dart'; @@ -16,7 +17,6 @@ class SessionView extends StatefulWidget { @override State createState() => _SessionViewState(); } - class _SessionViewState extends State { Future? _sessionFuture; @@ -159,22 +159,6 @@ class _SessionViewState extends State { ], ), ), - Padding( - padding: const EdgeInsets.only(left: 16.0, right: 16.0, bottom: 8), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - "Headless: ", - style: Theme.of(context).textTheme.labelLarge, - ), - Text( - session.headlessHost ? "Yes" : "No", - style: Theme.of(context).textTheme.labelMedium, - ), - ], - ), - ), ListSectionHeader( leadingText: "Users", trailingText: @@ -188,6 +172,11 @@ class _SessionViewState extends State { session.sessionUsers .map((user) => ListTile( dense: true, + leading: user.username == session.hostUsername && session.headlessHost + ? const Icon(Icons.dns, color: Color(0xFF294D5C)) + : user.username == session.hostUsername && !session.headlessHost + ? const Icon(Icons.star, color: Color(0xFFE69E50)) + : const Icon(Icons.person), title: Text( user.username, textAlign: TextAlign.start, @@ -195,6 +184,9 @@ class _SessionViewState extends State { subtitle: Text( user.isPresent ? "Active" : "Inactive", textAlign: TextAlign.start, + style: TextStyle( + color: user.isPresent ? Color.fromARGB(255, 89, 235, 91) : Color.fromARGB(255, 255, 118, 118), + ) ), )) .toList(), diff --git a/lib/widgets/update_notifier.dart b/lib/widgets/update_notifier.dart index f07ad32..c0f5fc5 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://git.mrdab.vore.media/ThatOneJackalGuy/OpenContacts/releases/latest"), mode: LaunchMode.externalApplication, ); }, diff --git a/linux/CMakeLists.txt b/linux/CMakeLists.txt index d199e8b..9a7e1a2 100644 --- a/linux/CMakeLists.txt +++ b/linux/CMakeLists.txt @@ -4,7 +4,7 @@ project(runner LANGUAGES CXX) # The name of the executable created for the application. Change this to change # the on-disk name of your application. -set(BINARY_NAME "recon") +set(BINARY_NAME "OpenContacts") # The unique GTK application identifier for this application. See: # https://wiki.gnome.org/HowDoI/ChooseApplicationID set(APPLICATION_ID "de.tojcklguy.opencontacts") diff --git a/linux/my_application.cc b/linux/my_application.cc index dbd4e93..75d4da3 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, "OpenContacts"); 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, "OpenContacts"); } gtk_window_set_default_size(window, 480, 900); diff --git a/pubspec.lock b/pubspec.lock index ceb58c1..dd4857d 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1,6 +1,14 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: + archive: + dependency: transitive + description: + name: archive + sha256: cb6a278ef2dbb298455e1a713bda08524a175630ec643a242c399c932a0a1f7d + url: "https://pub.dev" + source: hosted + version: "3.6.1" args: dependency: transitive description: @@ -278,6 +286,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.1.1" + flutter_launcher_icons: + dependency: "direct dev" + description: + name: flutter_launcher_icons + sha256: "559c600f056e7c704bd843723c21e01b5fba47e8824bd02422165bcc02a5de1d" + url: "https://pub.dev" + source: hosted + version: "0.9.3" flutter_lints: dependency: "direct dev" description: @@ -424,6 +440,14 @@ packages: url: "https://pub.dev" source: hosted version: "4.0.2" + image: + dependency: transitive + description: + name: image + sha256: "8e9d133755c3e84c73288363e6343157c383a0c6c56fc51afcc5d4d7180306d6" + url: "https://pub.dev" + source: hosted + version: "3.3.0" image_picker: dependency: "direct main" description: @@ -1093,6 +1117,14 @@ packages: url: "https://pub.dev" source: hosted version: "6.3.0" + yaml: + dependency: transitive + description: + name: yaml + sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5" + url: "https://pub.dev" + source: hosted + version: "3.1.2" sdks: dart: ">=3.3.0 <4.0.0" flutter: ">=3.18.0-18.0.pre.54" diff --git a/pubspec.yaml b/pubspec.yaml index e729211..3edfd87 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -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.0.1-alpha+2 +version: 0.0.3 environment: sdk: ">=3.0.1" @@ -69,6 +69,7 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter + flutter_launcher_icons: "^0.9.2" # The "flutter_lints" package below contains a set of recommended lints to # encourage good coding practices. The lint set provided by the package is @@ -91,6 +92,7 @@ flutter: assets: - assets/images/ + # An image asset can refer to one or more resolution-specific "variants", see # https://flutter.dev/assets-and-images/#resolution-aware @@ -116,3 +118,7 @@ flutter: # # For details regarding fonts from package dependencies, # see https://flutter.dev/custom-fonts/#from-packages +flutter_icons: + android: "launcher_icon" + ios: true + image_path: "assets/images/logo.png" \ No newline at end of file diff --git a/web/manifest.json b/web/manifest.json index b2d225b..2a7081d 100644 --- a/web/manifest.json +++ b/web/manifest.json @@ -1,6 +1,6 @@ { - "name": "recon", - "short_name": "recon", + "name": "OpenContacts", + "short_name": "opc", "start_url": ".", "display": "standalone", "background_color": "#0175C2", diff --git a/windows/flutter/CMakeLists.txt b/windows/flutter/CMakeLists.txt index 930d207..903f489 100644 --- a/windows/flutter/CMakeLists.txt +++ b/windows/flutter/CMakeLists.txt @@ -10,6 +10,11 @@ include(${EPHEMERAL_DIR}/generated_config.cmake) # https://github.com/flutter/flutter/issues/57146. set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") +# Set fallback configurations for older versions of the flutter tool. +if (NOT DEFINED FLUTTER_TARGET_PLATFORM) + set(FLUTTER_TARGET_PLATFORM "windows-x64") +endif() + # === Flutter Library === set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll") @@ -92,7 +97,7 @@ add_custom_command( COMMAND ${CMAKE_COMMAND} -E env ${FLUTTER_TOOL_ENVIRONMENT} "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" - windows-x64 $ + ${FLUTTER_TARGET_PLATFORM} $ VERBATIM ) add_custom_target(flutter_assemble DEPENDS diff --git a/windows/runner/main.cpp b/windows/runner/main.cpp index d97c34f..75a7078 100644 --- a/windows/runner/main.cpp +++ b/windows/runner/main.cpp @@ -27,7 +27,7 @@ int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, FlutterWindow window(project); Win32Window::Point origin(10, 10); Win32Window::Size size(1280, 720); - if (!window.Create(L"recon", origin, size)) { + if (!window.Create(L"OpenContacts", origin, size)) { return EXIT_FAILURE; } window.SetQuitOnClose(true);