Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature room bot can be removed after disconnection #4

Merged
merged 20 commits into from
Nov 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,14 @@ android {
signingConfig signingConfigs.release
}
}

// https://stackoverflow.com/a/77494454/8222484
packagingOptions {
pickFirst 'lib/x86/libc++_shared.so'
pickFirst 'lib/x86_64/libc++_shared.so'
pickFirst 'lib/armeabi-v7a/libc++_shared.so'
pickFirst 'lib/arm64-v8a/libc++_shared.so'
}
}

flutter {
Expand Down
24 changes: 23 additions & 1 deletion assets/l10n/intl_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -2550,5 +2550,27 @@
"editTodo": "Edit todo",
"pleaseAddATitle": "Please add a title",
"todoListChangedError": "Oops... The todo list has been changed while you edited it.",
"todosUnencrypted": "Please notice that todos are visible by everyone in the chat and are not end to end encrypted."
"todosUnencrypted": "Please notice that todos are visible by everyone in the chat and are not end to end encrypted.",
"youDonTHaveConversation": "You don't have any conversation yet.",
"connectChatNetworks": "Connect your chat networks",
"addSocialMessagingAccounts": "Add your social messaging accounts",
"addSocialMessagingAccountsText": "Connect all your conversations!",
"connected": "Connected",
"notConnected": "Not connected",
"connectYourSocialAccount": "Login to your account",
"enterYourDetails": "Enter your details :",
"pleaseEnterPassword": "Please enter your password",
"usernameNotFound": "The username you entered doesn't appear to belong to an account. Please check your username and try again.",
"passwordIncorrect": "Password incorrect",
"rateLimit": "An error has occurred, please wait a few minutes before trying again",
"err_": "Error",
"err_desc": "An error has occurred:",
"err_toConnect": "A problem occurred when connecting to",
"err_timeOut": "A network problem has been detected",
"err_tryAgain": "Please try again",
"bridgeBot_menuItemTitle" : "Connected social networks",
"bridgeBot_deleteConvTitle": "Delete Conversation",
"bridgeBot_deleteConvDescription": "Do you want to delete the conversation with the bot?",
"instagram": "Instagram",
"whatsApp": "WhatsApp"
}
2 changes: 1 addition & 1 deletion lib/config/app_config.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import 'dart:ui';
import 'package:matrix/matrix.dart';

abstract class AppConfig {
static String _applicationName = 'FluffyChat';
static String _applicationName = 'Tawkie';
static String get applicationName => _applicationName;
static String? _applicationWelcomeMessage;
static String? get applicationWelcomeMessage => _applicationWelcomeMessage;
Expand Down
13 changes: 13 additions & 0 deletions lib/config/routes.dart
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ import 'package:fluffychat/widgets/layouts/two_column_layout.dart';
import 'package:fluffychat/widgets/log_view.dart';
import 'package:fluffychat/widgets/matrix.dart';

import '../pages/add_bridge/add_bridge_body.dart';

abstract class AppRoutes {
static FutureOr<String?> loggedInRedirect(
BuildContext context,
Expand Down Expand Up @@ -263,6 +265,17 @@ abstract class AppRoutes {
),
],
),

// Route to social networking page via chat bot
// The entire path is: /rooms/settings/addbridgebot
GoRoute(
path: 'addbridgebot',
pageBuilder: (context, state) => defaultPageBuilder(
context,
const AddBridgeBody(),
),
redirect: loggedOutRedirect,
),
GoRoute(
path: 'security',
redirect: loggedOutRedirect,
Expand Down
197 changes: 197 additions & 0 deletions lib/pages/add_bridge/add_bridge_body.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
import 'dart:async';

import 'package:fluffychat/pages/add_bridge/service/bot_bridge_connection.dart';
import 'package:fluffychat/pages/add_bridge/service/hostname.dart';
import 'package:fluffychat/pages/add_bridge/show_bottom_sheet.dart';
import 'package:fluffychat/pages/add_bridge/show_delete_conversation_dialog.dart';
import 'package:fluffychat/utils/platform_infos.dart';
import 'package:fluffychat/utils/platform_size.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

import '../../widgets/matrix.dart';
import 'add_bridge_header.dart';
import 'connection_bridge_dialog.dart';
import 'error_message_dialog.dart';
import 'model/social_network.dart';

// Page offering brigde bot connections to social network chats
class AddBridgeBody extends StatefulWidget {
const AddBridgeBody({
super.key,
});

@override
State<AddBridgeBody> createState() => _AddBridgeBodyState();
}

class _AddBridgeBodyState extends State<AddBridgeBody> {
late BotBridgeConnection botConnection;
late String hostname;
bool timeoutErrorOccurred = false;

@override
void initState() {
final client = Matrix.of(context).client;
String fullUrl = client.homeserver!.host;
hostname = extractHostName(fullUrl);
botConnection = BotBridgeConnection(client: client, hostname: hostname);
super.initState();
_initStateAsync();
}

@override
void dispose() {
botConnection.stopProcess();
super.dispose();
}

// Online status update when page is opened
Future<void> _initStateAsync() async {
try {
final instagramConnected = await botConnection.pingWithTimeout(
context,
botConnection.instagramPing(),
);
if (!mounted) return; // Check if the widget is still mounted

if (instagramConnected != 'error') {
setState(() {
socialNetwork
.firstWhere((element) => element.name == "Instagram")
.connected = instagramConnected == 'Connected' ? true : false;
socialNetwork
.firstWhere((element) => element.name == "Instagram")
.loading = false;
});
} else if (mounted) {
showCatchErrorDialog(
context,
"${L10n.of(context)!.err_toConnect} ${L10n.of(context)!.instagram}",
);
}
} on TimeoutException {
// To indicate that the time-out error has occurred
if (mounted) {
timeoutErrorOccurred = true;
}
} catch (error) {
print("Error pinging Instagram: $error");
await Future.delayed(
const Duration(seconds: 1),
); // Precaution to let the page load
if (mounted && !timeoutErrorOccurred) {
showCatchErrorDialog(
context,
"${L10n.of(context)!.err_toConnect} ${L10n.of(context)!.instagram}",
);
}
}
}

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
buildHeaderBridgeText(context),
buildHeaderBridgeSubText(context),
Center(
child: SizedBox(
width: PlatformInfos.isWeb ? PlatformWidth.webWidth : null,
child: ListView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: socialNetwork.length,
itemBuilder: (BuildContext context, int index) {
return ListTile(
leading: socialNetwork[index].logo,
title: Text(
socialNetwork[index].name,
),
// Different build of subtle depending on the social network, for now only Instagram
subtitle: buildSubtitle(socialNetwork[index]),
trailing: const Icon(
CupertinoIcons.right_chevron,
),

// Different ways of connecting and disconnecting depending on the social network
onTap: () =>
handleSocialNetworkAction(socialNetwork[index]),
);
},
),
),
),
],
),
),
);
}

// Different ways of connecting and disconnecting depending on the social network, for now only Instagram
void handleSocialNetworkAction(SocialNetwork network) async {
if (network.loading == false) {
if (network.connected != true) {
bool success = false;
switch (network.name) {
case "Instagram":
// Trying to connect to Instagram
success = await connectToInstagram(context, network, botConnection);
break;

// For other networks
}
if (success) {
setState(() {
network.connected = true;
});
}
} else {
// Disconnect button, for the moment only this choice
final bool success = await showBottomSheetBridge(
context,
network,
botConnection,
);

if (success) {
setState(() {
network.connected = false;
});

// Show the dialog for deleting the conversation
await showDeleteConversationDialog(context, network, botConnection);
} else {
// Display error message to warn user
showCatchErrorDialog(context, L10n.of(context)!.err_timeOut);
}
}
}
}

// Different build of subtle depending on the social network, for now only Instagram
Widget buildSubtitle(SocialNetwork network) {
if (network.loading == true) {
return const Align(
alignment: Alignment.centerLeft,
child: CircularProgressIndicator(
color: Colors.grey,
),
);
} else {
return Text(
network.connected == true
? L10n.of(context)!.connected
: L10n.of(context)!.notConnected,
style: TextStyle(
color: network.connected == true ? Colors.green : Colors.grey,
),
);
}
}
}
30 changes: 30 additions & 0 deletions lib/pages/add_bridge/add_bridge_header.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';

// AddBridge page title and subtitle

Widget buildHeaderBridgeText(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(16.0),
child: Text(
L10n.of(context)!.addSocialMessagingAccounts,
textAlign: TextAlign.center,
style: const TextStyle(
fontSize: 24.0,
fontWeight: FontWeight.bold,
// color: Color(0xFFFAAB22),
),
),
);
}

Widget buildHeaderBridgeSubText(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(16.0),
child: Text(
L10n.of(context)!.addSocialMessagingAccountsText,
textAlign: TextAlign.center,
style: const TextStyle(fontSize: 16.0),
),
);
}
Loading
Loading