Compare commits
No commits in common. "main" and "Beta0.0.3" have entirely different histories.
|
@ -1,15 +0,0 @@
|
||||||
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"
|
|
13
README.md
|
@ -1,17 +1,14 @@
|
||||||
<img src="https://raw.githubusercontent.com/Mrdabup/OpenContacts/refs/heads/dev/assets/images/logo512.png" width="200"/>
|
<img src="https://git.mrdab.vore.media/ThatOneJackalGuy/OpenContacts/raw/branch/dev/assets/images/testingIcon512.png" width="200"/>
|
||||||
|
|
||||||
# OpenContacts
|
## OpenContacts
|
||||||
|
|
||||||
A Resonite Contacts App, based on Nutcake's Recon.
|
A Resonite Contacts App, based on Nutcake's Recon.
|
||||||
|
|
||||||
[Get the latest version of OpenContacts here](https://git.mrdab.vore.media/ThatOneJackalGuy/OpenContacts/releases)
|
[Get the latest version of OpenContacts here](https://git.mrdab.vore.media/ThatOneJackalGuy/OpenContacts)
|
||||||
|
|
||||||
[Available on github too!](https://github.com/Mrdabup/OpenContacts/releases)
|
|
||||||
|
|
||||||
[Get ReCon here](https://github.com/Nutcake/ReCon)
|
[Get ReCon here](https://github.com/Nutcake/ReCon)
|
||||||
|
|
||||||
|
# Building
|
||||||
## Building
|
|
||||||
|
|
||||||
This is a standard Flutter application, refer to the [Flutter docs](https://docs.flutter.dev/get-started/install) on how to build it.
|
This is a standard Flutter application, refer to the [Flutter docs](https://docs.flutter.dev/get-started/install) on how to build it.
|
||||||
|
|
||||||
|
@ -20,7 +17,7 @@ Currently only Android is fully supported.
|
||||||
The app works on other platforms, though not every feature will be functional.
|
The app works on other platforms, though not every feature will be functional.
|
||||||
For example, notifications are currently not supported on non-android builds.
|
For example, notifications are currently not supported on non-android builds.
|
||||||
|
|
||||||
### Screenshots
|
# Screenshots
|
||||||
TODO: Screenshots!
|
TODO: Screenshots!
|
||||||
|
|
||||||
<!--<img src="https://github.com/Nutcake/ReCon/assets/10452593/a46ccf8a-0a9f-4518-98e6-84fad2d7bf26" width=198/> <img src="https://github.com/Nutcake/ReCon/assets/10452593/5d158f58-cd27-4a68-abf3-9068e92b6a82" width=198/> <img src="https://github.com/Nutcake/ReCon/assets/10452593/f2ce95ef-e513-46cb-9654-31e74cdc7c09" width=198/> <img src="https://github.com/Nutcake/ReCon/assets/10452593/58ef5e5e-1b53-4a47-92f8-bcbcba7a1e86" width=198/>-->
|
<!--<img src="https://github.com/Nutcake/ReCon/assets/10452593/a46ccf8a-0a9f-4518-98e6-84fad2d7bf26" width=198/> <img src="https://github.com/Nutcake/ReCon/assets/10452593/5d158f58-cd27-4a68-abf3-9068e92b6a82" width=198/> <img src="https://github.com/Nutcake/ReCon/assets/10452593/f2ce95ef-e513-46cb-9654-31e74cdc7c09" width=198/> <img src="https://github.com/Nutcake/ReCon/assets/10452593/58ef5e5e-1b53-4a47-92f8-bcbcba7a1e86" width=198/>-->
|
|
@ -9,7 +9,7 @@
|
||||||
<application
|
<application
|
||||||
android:label="OpenContacts"
|
android:label="OpenContacts"
|
||||||
android:name="${applicationName}"
|
android:name="${applicationName}"
|
||||||
android:icon="@mipmap/launcher_icon">
|
android:icon="@mipmap/ic_launcher">
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
|
|
Before Width: | Height: | Size: 4.2 KiB |
Before Width: | Height: | Size: 2.6 KiB |
Before Width: | Height: | Size: 5.7 KiB |
Before Width: | Height: | Size: 8.9 KiB |
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 75 KiB After Width: | Height: | Size: 150 KiB |
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 64 KiB |
|
@ -765,4 +765,4 @@
|
||||||
/* End XCConfigurationList section */
|
/* End XCConfigurationList section */
|
||||||
};
|
};
|
||||||
rootObject = 97C146E61CF9000F007C117D /* Project object */;
|
rootObject = 97C146E61CF9000F007C117D /* Project object */;
|
||||||
}
|
}
|
||||||
|
|
Before Width: | Height: | Size: 74 KiB |
Before Width: | Height: | Size: 991 B |
Before Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 3.4 KiB |
Before Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 3.2 KiB |
Before Width: | Height: | Size: 5.1 KiB |
Before Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 4.6 KiB |
Before Width: | Height: | Size: 7.3 KiB |
Before Width: | Height: | Size: 7.3 KiB |
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 4.4 KiB |
Before Width: | Height: | Size: 9.4 KiB |
Before Width: | Height: | Size: 10 KiB |
|
@ -131,7 +131,6 @@ class Session {
|
||||||
enum SessionAccessLevel {
|
enum SessionAccessLevel {
|
||||||
unknown,
|
unknown,
|
||||||
private,
|
private,
|
||||||
lan,
|
|
||||||
contacts,
|
contacts,
|
||||||
contactsPlus,
|
contactsPlus,
|
||||||
registeredUsers,
|
registeredUsers,
|
||||||
|
@ -140,7 +139,6 @@ enum SessionAccessLevel {
|
||||||
static const _readableNamesMap = {
|
static const _readableNamesMap = {
|
||||||
SessionAccessLevel.unknown: "Unknown",
|
SessionAccessLevel.unknown: "Unknown",
|
||||||
SessionAccessLevel.private: "Private",
|
SessionAccessLevel.private: "Private",
|
||||||
SessionAccessLevel.lan: "LAN",
|
|
||||||
SessionAccessLevel.contacts: "Contacts only",
|
SessionAccessLevel.contacts: "Contacts only",
|
||||||
SessionAccessLevel.contactsPlus: "Contacts+",
|
SessionAccessLevel.contactsPlus: "Contacts+",
|
||||||
SessionAccessLevel.registeredUsers: "Registered users",
|
SessionAccessLevel.registeredUsers: "Registered users",
|
||||||
|
|
|
@ -10,15 +10,13 @@ import 'package:OpenContacts/widgets/formatted_text.dart';
|
||||||
import 'package:OpenContacts/widgets/friends/friend_online_status_indicator.dart';
|
import 'package:OpenContacts/widgets/friends/friend_online_status_indicator.dart';
|
||||||
import 'package:OpenContacts/widgets/generic_avatar.dart';
|
import 'package:OpenContacts/widgets/generic_avatar.dart';
|
||||||
import 'package:OpenContacts/widgets/messages/messages_list.dart';
|
import 'package:OpenContacts/widgets/messages/messages_list.dart';
|
||||||
import 'package:OpenContacts/widgets/my_profile_dialog.dart';
|
|
||||||
|
|
||||||
class FriendListTile extends StatelessWidget {
|
class FriendListTile extends StatelessWidget {
|
||||||
const FriendListTile({required this.friend, required this.unreads, this.onTap, super.key, this.onLongPress});
|
const FriendListTile({required this.friend, required this.unreads, this.onTap, super.key});
|
||||||
|
|
||||||
final Friend friend;
|
final Friend friend;
|
||||||
final int unreads;
|
final int unreads;
|
||||||
final Function? onTap;
|
final Function? onTap;
|
||||||
final Function? onLongPress;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
@ -131,14 +129,6 @@ class FriendListTile extends StatelessWidget {
|
||||||
);
|
);
|
||||||
mClient.selectedFriend = null;
|
mClient.selectedFriend = null;
|
||||||
},
|
},
|
||||||
onLongPress: () async {
|
|
||||||
await showDialog(
|
|
||||||
context: context,
|
|
||||||
builder: (context) {
|
|
||||||
return const MyProfileDialog();
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ class FriendOnlineStatusIndicator extends StatelessWidget {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final UserStatus userStatus = friend.userStatus;
|
final UserStatus userStatus = friend.userStatus;
|
||||||
final OnlineStatus onlineStatus = userStatus.onlineStatus;
|
final OnlineStatus onlineStatus = userStatus.onlineStatus;
|
||||||
return userStatus.appVersion.contains("OpenContacts") && friend.isOnline
|
return userStatus.appVersion.contains("recon") && friend.isOnline
|
||||||
? SizedBox.square(
|
? SizedBox.square(
|
||||||
dimension: 10,
|
dimension: 10,
|
||||||
child: Image.asset(
|
child: Image.asset(
|
||||||
|
@ -29,4 +29,3 @@ class FriendOnlineStatusIndicator extends StatelessWidget {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// TODO: Re-invent the fucking wheel aparently
|
|
|
@ -21,7 +21,7 @@ class _FriendsListAppBarState extends State<FriendsListAppBar> with AutomaticKee
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
super.build(context);
|
super.build(context);
|
||||||
return AppBar(
|
return AppBar(
|
||||||
title: const Text("Contacts"),
|
title: const Text("OpenContacts"),
|
||||||
actions: [
|
actions: [
|
||||||
Consumer<MessagingClient>(builder: (context, client, _) {
|
Consumer<MessagingClient>(builder: (context, client, _) {
|
||||||
return PopupMenuButton<OnlineStatus>(
|
return PopupMenuButton<OnlineStatus>(
|
||||||
|
@ -84,7 +84,7 @@ class _FriendsListAppBarState extends State<FriendsListAppBar> with AutomaticKee
|
||||||
await itemDef.onTap();
|
await itemDef.onTap();
|
||||||
},
|
},
|
||||||
itemBuilder: (BuildContext context) => [
|
itemBuilder: (BuildContext context) => [
|
||||||
/*MenuItemDefinition(
|
MenuItemDefinition(
|
||||||
name: "Add Users",
|
name: "Add Users",
|
||||||
icon: Icons.person_add,
|
icon: Icons.person_add,
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
|
@ -98,8 +98,7 @@ class _FriendsListAppBarState extends State<FriendsListAppBar> with AutomaticKee
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),*/
|
),
|
||||||
//TODO: Add users API
|
|
||||||
MenuItemDefinition(
|
MenuItemDefinition(
|
||||||
name: "My Profile",
|
name: "My Profile",
|
||||||
icon: Icons.person,
|
icon: Icons.person,
|
||||||
|
|
|
@ -28,13 +28,13 @@ class _UserListTileState extends State<UserListTile> {
|
||||||
.of(context)
|
.of(context)
|
||||||
.colorScheme;
|
.colorScheme;
|
||||||
final style = _localAdded ? IconButton.styleFrom(
|
final style = _localAdded ? IconButton.styleFrom(
|
||||||
foregroundColor: colorScheme.onSurface,
|
foregroundColor: colorScheme.onBackground,
|
||||||
side: BorderSide(
|
side: BorderSide(
|
||||||
color: colorScheme.error,
|
color: colorScheme.error,
|
||||||
width: 2
|
width: 2
|
||||||
),
|
),
|
||||||
) : IconButton.styleFrom(
|
) : IconButton.styleFrom(
|
||||||
foregroundColor: colorScheme.onSurface,
|
foregroundColor: colorScheme.onBackground,
|
||||||
side: BorderSide(
|
side: BorderSide(
|
||||||
color: colorScheme.primary,
|
color: colorScheme.primary,
|
||||||
width: 2
|
width: 2
|
||||||
|
@ -50,7 +50,7 @@ class _UserListTileState extends State<UserListTile> {
|
||||||
icon: _localAdded ? const Icon(Icons.person_remove) : const Icon(Icons.person_add),
|
icon: _localAdded ? const Icon(Icons.person_remove) : const Icon(Icons.person_add),
|
||||||
style: style,
|
style: style,
|
||||||
onPressed: _loading ? null : () async {
|
onPressed: _loading ? null : () async {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text("Sorry, this feature is unavailable.")));
|
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text("Sorry, this feature is not yet available")));
|
||||||
return;
|
return;
|
||||||
setState(() {
|
setState(() {
|
||||||
_loading = true;
|
_loading = true;
|
||||||
|
|
|
@ -65,8 +65,8 @@ class _HomeState extends State<Home> {
|
||||||
label: "Sessions",
|
label: "Sessions",
|
||||||
),
|
),
|
||||||
NavigationDestination(
|
NavigationDestination(
|
||||||
icon: Icon(Icons.contacts),
|
icon: Icon(Icons.message),
|
||||||
label: "Contacts",
|
label: "Chat",
|
||||||
),
|
),
|
||||||
NavigationDestination(
|
NavigationDestination(
|
||||||
icon: Icon(Icons.inventory),
|
icon: Icon(Icons.inventory),
|
||||||
|
|
|
@ -192,18 +192,12 @@ class _InventoryBrowserState extends State<InventoryBrowser> with AutomaticKeepA
|
||||||
: () async {
|
: () async {
|
||||||
await Navigator.push(
|
await Navigator.push(
|
||||||
context,
|
context,
|
||||||
MaterialPageRoute(
|
MaterialPageRoute(
|
||||||
builder: (context) => Scaffold(
|
builder: (context) => PhotoView(
|
||||||
appBar: AppBar(
|
minScale: PhotoViewComputedScale.contained,
|
||||||
title: Text(record.formattedName.toString()),
|
imageProvider:
|
||||||
),
|
CachedNetworkImageProvider(Aux.resdbToHttp(record.thumbnailUri)),
|
||||||
body: Center (
|
heroAttributes: PhotoViewHeroAttributes(tag: record.id),
|
||||||
child: CachedNetworkImage(
|
|
||||||
imageUrl: (Aux.resdbToHttp(record.thumbnailUri)),
|
|
||||||
placeholder: (context, url) => const CircularProgressIndicator(),
|
|
||||||
errorWidget: (context, url, error) => const Icon(Icons.error),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
@ -27,6 +27,7 @@ class _LoginScreenState extends State<LoginScreen> {
|
||||||
late final FocusNode _totpFocusNode;
|
late final FocusNode _totpFocusNode;
|
||||||
|
|
||||||
bool _isLoading = false;
|
bool _isLoading = false;
|
||||||
|
bool _isEmailResetSend = false;
|
||||||
String _error = "";
|
String _error = "";
|
||||||
bool _needsTotp = false;
|
bool _needsTotp = false;
|
||||||
|
|
||||||
|
@ -46,6 +47,13 @@ class _LoginScreenState extends State<LoginScreen> {
|
||||||
_totpFocusNode.dispose();
|
_totpFocusNode.dispose();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
RegExp emailReg = RegExp(
|
||||||
|
r"^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$",
|
||||||
|
|
||||||
|
caseSensitive: false,
|
||||||
|
multiLine: false,
|
||||||
|
|
||||||
|
);
|
||||||
Future<void> submit() async {
|
Future<void> submit() async {
|
||||||
|
|
||||||
if (_usernameController.text.isEmpty || _passwordController.text.isEmpty) {
|
if (_usernameController.text.isEmpty || _passwordController.text.isEmpty) {
|
||||||
|
@ -103,7 +111,69 @@ class _LoginScreenState extends State<LoginScreen> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Future<void> 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<void> loginSuccessful(AuthenticationData authData) async {
|
Future<void> loginSuccessful(AuthenticationData authData) async {
|
||||||
final settingsClient = ClientHolder.of(context).settingsClient;
|
final settingsClient = ClientHolder.of(context).settingsClient;
|
||||||
final notificationManager = FlutterLocalNotificationsPlugin();
|
final notificationManager = FlutterLocalNotificationsPlugin();
|
||||||
|
@ -227,6 +297,16 @@ class _LoginScreenState extends State<LoginScreen> {
|
||||||
label: const Text("Login"),
|
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(
|
Center(
|
||||||
child: AnimatedOpacity(
|
child: AnimatedOpacity(
|
||||||
opacity: _errorOpacity,
|
opacity: _errorOpacity,
|
||||||
|
|
|
@ -6,7 +6,6 @@ import 'package:OpenContacts/client_holder.dart';
|
||||||
import 'package:OpenContacts/models/personal_profile.dart';
|
import 'package:OpenContacts/models/personal_profile.dart';
|
||||||
import 'package:OpenContacts/widgets/default_error_widget.dart';
|
import 'package:OpenContacts/widgets/default_error_widget.dart';
|
||||||
import 'package:OpenContacts/widgets/generic_avatar.dart';
|
import 'package:OpenContacts/widgets/generic_avatar.dart';
|
||||||
import 'package:OpenContacts/models/users/friend.dart';
|
|
||||||
|
|
||||||
class MyProfileDialog extends StatefulWidget {
|
class MyProfileDialog extends StatefulWidget {
|
||||||
const MyProfileDialog({super.key});
|
const MyProfileDialog({super.key});
|
||||||
|
@ -31,7 +30,7 @@ class _MyProfileDialogState extends State<MyProfileDialog> {
|
||||||
_storageQuotaFuture = UserApi.getStorageQuota(apiClient);
|
_storageQuotaFuture = UserApi.getStorageQuota(apiClient);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final tt = Theme.of(context).textTheme;
|
final tt = Theme.of(context).textTheme;
|
||||||
|
|
|
@ -7,7 +7,6 @@ import 'package:OpenContacts/widgets/formatted_text.dart';
|
||||||
import 'package:OpenContacts/widgets/sessions/session_view.dart';
|
import 'package:OpenContacts/widgets/sessions/session_view.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:flutter/services.dart';
|
|
||||||
|
|
||||||
class SessionList extends StatefulWidget {
|
class SessionList extends StatefulWidget {
|
||||||
const SessionList({super.key});
|
const SessionList({super.key});
|
||||||
|
@ -15,11 +14,6 @@ class SessionList extends StatefulWidget {
|
||||||
@override
|
@override
|
||||||
State<SessionList> createState() => _SessionListState();
|
State<SessionList> createState() => _SessionListState();
|
||||||
}
|
}
|
||||||
class onKeyIntent extends Intent{
|
|
||||||
const onKeyIntent();
|
|
||||||
}
|
|
||||||
|
|
||||||
const onKey = SingleActivator(LogicalKeyboardKey.f5);
|
|
||||||
|
|
||||||
class _SessionListState extends State<SessionList> with AutomaticKeepAliveClientMixin {
|
class _SessionListState extends State<SessionList> with AutomaticKeepAliveClientMixin {
|
||||||
@override
|
@override
|
||||||
|
@ -59,7 +53,7 @@ class _SessionListState extends State<SessionList> with AutomaticKeepAliveClient
|
||||||
? const DefaultErrorWidget(
|
? const DefaultErrorWidget(
|
||||||
title: "No Sessions Found",
|
title: "No Sessions Found",
|
||||||
message: "Try to adjust your filters",
|
message: "Try to adjust your filters",
|
||||||
iconOverride: Icons.question_mark,
|
iconOverride: Icons.public_off,
|
||||||
)
|
)
|
||||||
: Padding(
|
: Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
||||||
|
@ -69,7 +63,7 @@ class _SessionListState extends State<SessionList> with AutomaticKeepAliveClient
|
||||||
gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent(
|
gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent(
|
||||||
maxCrossAxisExtent: 256,
|
maxCrossAxisExtent: 256,
|
||||||
crossAxisSpacing: 4,
|
crossAxisSpacing: 4,
|
||||||
mainAxisSpacing: 1,
|
mainAxisSpacing: 4,
|
||||||
childAspectRatio: .8,
|
childAspectRatio: .8,
|
||||||
),
|
),
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
|
@ -132,24 +126,7 @@ class _SessionListState extends State<SessionList> with AutomaticKeepAliveClient
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 2,
|
height: 4,
|
||||||
),
|
|
||||||
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(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import 'package:OpenContacts/models/users/user.dart';
|
|
||||||
import 'package:cached_network_image/cached_network_image.dart';
|
import 'package:cached_network_image/cached_network_image.dart';
|
||||||
import 'package:OpenContacts/apis/session_api.dart';
|
import 'package:OpenContacts/apis/session_api.dart';
|
||||||
import 'package:OpenContacts/auxiliary.dart';
|
import 'package:OpenContacts/auxiliary.dart';
|
||||||
|
@ -17,6 +16,7 @@ class SessionView extends StatefulWidget {
|
||||||
@override
|
@override
|
||||||
State<SessionView> createState() => _SessionViewState();
|
State<SessionView> createState() => _SessionViewState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _SessionViewState extends State<SessionView> {
|
class _SessionViewState extends State<SessionView> {
|
||||||
Future<Session>? _sessionFuture;
|
Future<Session>? _sessionFuture;
|
||||||
|
|
||||||
|
@ -159,6 +159,22 @@ class _SessionViewState extends State<SessionView> {
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
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(
|
ListSectionHeader(
|
||||||
leadingText: "Users",
|
leadingText: "Users",
|
||||||
trailingText:
|
trailingText:
|
||||||
|
@ -172,11 +188,6 @@ class _SessionViewState extends State<SessionView> {
|
||||||
session.sessionUsers
|
session.sessionUsers
|
||||||
.map((user) => ListTile(
|
.map((user) => ListTile(
|
||||||
dense: true,
|
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(
|
title: Text(
|
||||||
user.username,
|
user.username,
|
||||||
textAlign: TextAlign.start,
|
textAlign: TextAlign.start,
|
||||||
|
@ -184,9 +195,6 @@ class _SessionViewState extends State<SessionView> {
|
||||||
subtitle: Text(
|
subtitle: Text(
|
||||||
user.isPresent ? "Active" : "Inactive",
|
user.isPresent ? "Active" : "Inactive",
|
||||||
textAlign: TextAlign.start,
|
textAlign: TextAlign.start,
|
||||||
style: TextStyle(
|
|
||||||
color: user.isPresent ? Color.fromARGB(255, 89, 235, 91) : Color.fromARGB(255, 255, 118, 118),
|
|
||||||
)
|
|
||||||
),
|
),
|
||||||
))
|
))
|
||||||
.toList(),
|
.toList(),
|
||||||
|
|
|
@ -38,7 +38,7 @@ class UpdateNotifier extends StatelessWidget {
|
||||||
children: [
|
children: [
|
||||||
TextButton.icon(
|
TextButton.icon(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
launchUrl(Uri.parse("https://git.mrdab.vore.media/ThatOneJackalGuy/OpenContacts/releases/latest"),
|
launchUrl(Uri.parse("https://github.com/Nutcake/recon/releases/latest"),
|
||||||
mode: LaunchMode.externalApplication,
|
mode: LaunchMode.externalApplication,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
|
@ -4,7 +4,7 @@ project(runner LANGUAGES CXX)
|
||||||
|
|
||||||
# The name of the executable created for the application. Change this to change
|
# The name of the executable created for the application. Change this to change
|
||||||
# the on-disk name of your application.
|
# the on-disk name of your application.
|
||||||
set(BINARY_NAME "OpenContacts")
|
set(BINARY_NAME "recon")
|
||||||
# The unique GTK application identifier for this application. See:
|
# The unique GTK application identifier for this application. See:
|
||||||
# https://wiki.gnome.org/HowDoI/ChooseApplicationID
|
# https://wiki.gnome.org/HowDoI/ChooseApplicationID
|
||||||
set(APPLICATION_ID "de.tojcklguy.opencontacts")
|
set(APPLICATION_ID "de.tojcklguy.opencontacts")
|
||||||
|
|
|
@ -40,11 +40,11 @@ static void my_application_activate(GApplication* application) {
|
||||||
if (use_header_bar) {
|
if (use_header_bar) {
|
||||||
GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new());
|
GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new());
|
||||||
gtk_widget_show(GTK_WIDGET(header_bar));
|
gtk_widget_show(GTK_WIDGET(header_bar));
|
||||||
gtk_header_bar_set_title(header_bar, "OpenContacts");
|
gtk_header_bar_set_title(header_bar, "recon");
|
||||||
gtk_header_bar_set_show_close_button(header_bar, TRUE);
|
gtk_header_bar_set_show_close_button(header_bar, TRUE);
|
||||||
gtk_window_set_titlebar(window, GTK_WIDGET(header_bar));
|
gtk_window_set_titlebar(window, GTK_WIDGET(header_bar));
|
||||||
} else {
|
} else {
|
||||||
gtk_window_set_title(window, "OpenContacts");
|
gtk_window_set_title(window, "recon");
|
||||||
}
|
}
|
||||||
|
|
||||||
gtk_window_set_default_size(window, 480, 900);
|
gtk_window_set_default_size(window, 480, 900);
|
||||||
|
|
32
pubspec.lock
|
@ -1,14 +1,6 @@
|
||||||
# Generated by pub
|
# Generated by pub
|
||||||
# See https://dart.dev/tools/pub/glossary#lockfile
|
# See https://dart.dev/tools/pub/glossary#lockfile
|
||||||
packages:
|
packages:
|
||||||
archive:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: archive
|
|
||||||
sha256: cb6a278ef2dbb298455e1a713bda08524a175630ec643a242c399c932a0a1f7d
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "3.6.1"
|
|
||||||
args:
|
args:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -286,14 +278,6 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.1.1"
|
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:
|
flutter_lints:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
|
@ -440,14 +424,6 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.0.2"
|
version: "4.0.2"
|
||||||
image:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: image
|
|
||||||
sha256: "8e9d133755c3e84c73288363e6343157c383a0c6c56fc51afcc5d4d7180306d6"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "3.3.0"
|
|
||||||
image_picker:
|
image_picker:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -1117,14 +1093,6 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.3.0"
|
version: "6.3.0"
|
||||||
yaml:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: yaml
|
|
||||||
sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "3.1.2"
|
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=3.3.0 <4.0.0"
|
dart: ">=3.3.0 <4.0.0"
|
||||||
flutter: ">=3.18.0-18.0.pre.54"
|
flutter: ">=3.18.0-18.0.pre.54"
|
||||||
|
|
|
@ -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
|
# 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
|
# 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.
|
# of the product and file versions while build-number is used as the build suffix.
|
||||||
version: 0.0.3
|
version: 0.0.1-alpha+2
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ">=3.0.1"
|
sdk: ">=3.0.1"
|
||||||
|
@ -69,7 +69,6 @@ dependencies:
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
flutter_launcher_icons: "^0.9.2"
|
|
||||||
|
|
||||||
# The "flutter_lints" package below contains a set of recommended lints to
|
# The "flutter_lints" package below contains a set of recommended lints to
|
||||||
# encourage good coding practices. The lint set provided by the package is
|
# encourage good coding practices. The lint set provided by the package is
|
||||||
|
@ -92,7 +91,6 @@ flutter:
|
||||||
assets:
|
assets:
|
||||||
- assets/images/
|
- assets/images/
|
||||||
|
|
||||||
|
|
||||||
# An image asset can refer to one or more resolution-specific "variants", see
|
# An image asset can refer to one or more resolution-specific "variants", see
|
||||||
# https://flutter.dev/assets-and-images/#resolution-aware
|
# https://flutter.dev/assets-and-images/#resolution-aware
|
||||||
|
|
||||||
|
@ -118,7 +116,3 @@ flutter:
|
||||||
#
|
#
|
||||||
# For details regarding fonts from package dependencies,
|
# For details regarding fonts from package dependencies,
|
||||||
# see https://flutter.dev/custom-fonts/#from-packages
|
# see https://flutter.dev/custom-fonts/#from-packages
|
||||||
flutter_icons:
|
|
||||||
android: "launcher_icon"
|
|
||||||
ios: true
|
|
||||||
image_path: "assets/images/logo.png"
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "OpenContacts",
|
"name": "recon",
|
||||||
"short_name": "opc",
|
"short_name": "recon",
|
||||||
"start_url": ".",
|
"start_url": ".",
|
||||||
"display": "standalone",
|
"display": "standalone",
|
||||||
"background_color": "#0175C2",
|
"background_color": "#0175C2",
|
||||||
|
|
|
@ -10,11 +10,6 @@ include(${EPHEMERAL_DIR}/generated_config.cmake)
|
||||||
# https://github.com/flutter/flutter/issues/57146.
|
# https://github.com/flutter/flutter/issues/57146.
|
||||||
set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper")
|
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 ===
|
# === Flutter Library ===
|
||||||
set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll")
|
set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll")
|
||||||
|
|
||||||
|
@ -97,7 +92,7 @@ add_custom_command(
|
||||||
COMMAND ${CMAKE_COMMAND} -E env
|
COMMAND ${CMAKE_COMMAND} -E env
|
||||||
${FLUTTER_TOOL_ENVIRONMENT}
|
${FLUTTER_TOOL_ENVIRONMENT}
|
||||||
"${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat"
|
"${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat"
|
||||||
${FLUTTER_TARGET_PLATFORM} $<CONFIG>
|
windows-x64 $<CONFIG>
|
||||||
VERBATIM
|
VERBATIM
|
||||||
)
|
)
|
||||||
add_custom_target(flutter_assemble DEPENDS
|
add_custom_target(flutter_assemble DEPENDS
|
||||||
|
|
|
@ -27,7 +27,7 @@ int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev,
|
||||||
FlutterWindow window(project);
|
FlutterWindow window(project);
|
||||||
Win32Window::Point origin(10, 10);
|
Win32Window::Point origin(10, 10);
|
||||||
Win32Window::Size size(1280, 720);
|
Win32Window::Size size(1280, 720);
|
||||||
if (!window.Create(L"OpenContacts", origin, size)) {
|
if (!window.Create(L"recon", origin, size)) {
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
window.SetQuitOnClose(true);
|
window.SetQuitOnClose(true);
|
||||||
|
|