Skip to content

Commit

Permalink
Merge pull request #35 from Tawkie/feature-beta-group
Browse files Browse the repository at this point in the history
Feature beta group
  • Loading branch information
VincePaulin authored Jul 29, 2024
2 parents 86fa322 + 05c4f78 commit 66f7c70
Show file tree
Hide file tree
Showing 9 changed files with 329 additions and 7 deletions.
16 changes: 16 additions & 0 deletions assets/l10n/intl_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -2684,6 +2684,22 @@
"privacyTextAnd": " and ",
"privacyTextTerms": "terms of service",
"createGroupLimitationWarning": "Only Tawkie / Matrix users can be added to a group chat.",
"joinBetaTitle": "Join the Beta",
"betaJoinExplanation": "## How to test the Beta version and access new features in advance?",
"betaJoinBenefit": "Participating in the Beta allows you to access application updates in advance and be the first to test new features!",
"iosInstructionsTitle": "On iOS:",
"installTestflight": "- Install Apple Testflight",
"downloadTestflightButton": "Download Apple Testflight",
"downloadBetaIOSButton": "Download the iOS Beta",
"joinBetaGroup": "- Join the Tawkie Beta group: #beta",
"androidInstructionsTitle": "On Android:",
"joinBetaPlayStore": "- Join the Beta from the Play Store or online",
"downloadBetaAndroidButton": "Download the Android Beta",
"joinBetaButtonLabel": "Join the Beta group",
"joinBetaError": "Something went wrong: ",
"failedToJoinRoom": "Failed to join room: ",
"roomIdNullError": "Room ID is null for alias: ",
"roomNotFoundError": "Room not found after joining",
"seeBotsRoom":"See bots",
"leaveTheConvDesc": "Do you really want to leave this conversation?",
"leaveTheConvSuccess": "You have left the conversation.",
Expand Down
16 changes: 16 additions & 0 deletions assets/l10n/intl_fr.arb
Original file line number Diff line number Diff line change
Expand Up @@ -2500,6 +2500,22 @@
"privacyTextAnd": " et ",
"privacyTextTerms": "conditions générales d’utilisation et de services",
"createGroupLimitationWarning": "Seul.es les utilisateur.ices Tawkie peuvent être rajouté.es aux groupes.",
"joinBetaTitle": "Rejoindre la Beta",
"betaJoinExplanation": "## Comment tester la version Beta et accéder aux nouvelles fonctionnalités en avance ?",
"betaJoinBenefit": "Participer à la Beta permet d'avoir accès aux mises à jour de l'application en avance et tester en premier.ère les nouvelles fonctionnalités !",
"iosInstructionsTitle": "Sous iOS :",
"installTestflight": "- Installer Apple Testflight",
"downloadTestflightButton": "Télécharger Apple Testflight",
"downloadBetaIOSButton": "Télécharger la Beta iOS",
"joinBetaGroup": "- Rejoindre le groupe Tawkie de la Beta : #beta",
"androidInstructionsTitle": "Sous Android :",
"joinBetaPlayStore": "- Rejoindre la Beta depuis le Play Store ou en ligne",
"downloadBetaAndroidButton": "Télécharger la Beta Android",
"joinBetaButtonLabel": "Rejoindre le groupe Beta",
"joinBetaError": "Une erreur s'est produite : ",
"failedToJoinRoom": "Échec de la connexion à la salle : ",
"roomIdNullError": "L'ID de la salle est nul pour l'alias : ",
"roomNotFoundError": "Salle introuvable après la connexion",
"seeBotsRoom":"Voir les bots",
"leaveTheConvDesc": "Voulez-vous vraiment quitter cette conversation ?",
"leaveTheConvSuccess": "Vous avez quitté la conversation.",
Expand Down
17 changes: 17 additions & 0 deletions lib/config/app_config.dart
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,23 @@ abstract class AppConfig {
static const String baseUrl = kDebugMode ? stagingUrl : productionUrl;
static String tawkieSubscriptionIdentifier = 'Tawkie subscription';

// URLs for Beta Join
static const String testflightAppUrl = 'https://apps.apple.com/us/app/testflight/id899247664';
static const String appleBetaUrl = 'https://testflight.apple.com/join/daXe0NfW';
static const String playStoreUrl = 'https://play.google.com/store/apps/details?id=fr.tawkie.app';
static const String androidBetaUrl = 'https://play.google.com/apps/testing/fr.tawkie.app';

static const String iosUrl = 'itms-apps://itunes.apple.com/app/id899247664';
static const String androidUrl = 'market://details?id=fr.tawkie.app';

static const String prodBetaAlias = 'beta';
static const String testBetaAlias = 'testbeta';
static const String betaAlias = kDebugMode ? testBetaAlias : prodBetaAlias;
static const String serverStagingUrl = ':staging.tawkie.fr';
static const String serverProductionUrl = ':alpha.tawkie.fr';
static const String server = kDebugMode ? serverStagingUrl : serverProductionUrl;
static const String roomAlias = '#$betaAlias$server';

static void loadFromJson(Map<String, dynamic> json) {
if (json['chat_color'] != null) {
try {
Expand Down
16 changes: 12 additions & 4 deletions lib/config/routes.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,12 @@ import 'dart:async';

import 'package:flutter/material.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';

import 'package:go_router/go_router.dart';

import 'package:tawkie/config/themes.dart';
import 'package:tawkie/pages/add_bridge/add_bridge.dart';
import 'package:tawkie/pages/add_bridge/add_bridge_body.dart';
import 'package:tawkie/pages/archive/archive.dart';
import 'package:tawkie/pages/auth/auth.dart';
import 'package:tawkie/pages/beta/beta.dart';
import 'package:tawkie/pages/chat/chat.dart';
import 'package:tawkie/pages/chat_access_settings/chat_access_settings_controller.dart';
import 'package:tawkie/pages/chat_details/chat_details.dart';
Expand Down Expand Up @@ -49,7 +47,8 @@ abstract class AppRoutes {
final FlutterSecureStorage _secureStorage = const FlutterSecureStorage();
final sessionToken = await _secureStorage.read(key: 'sessionToken');

final bool isLoggedKratos = sessionToken is String && sessionToken.isNotEmpty;
final bool isLoggedKratos =
sessionToken is String && sessionToken.isNotEmpty;
final bool isLoggedMatrix = Matrix.of(context).client.isLogged();
final bool preAuth = state.fullPath!.startsWith('/home');

Expand Down Expand Up @@ -306,6 +305,15 @@ abstract class AppRoutes {
),
],
),
GoRoute(
path: 'joinBeta',
pageBuilder: (context, state) => defaultPageBuilder(
context,
state,
const BetaJoinPage(),
),
redirect: loggedOutRedirect,
),
// Route to social networking page via chat bot
// The entire path is: /rooms/settings/addbridgebot
GoRoute(
Expand Down
35 changes: 35 additions & 0 deletions lib/pages/beta/android_instructions.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:tawkie/config/app_config.dart';
import 'package:tawkie/pages/beta/instructions.dart';

class AndroidInstructions extends BetaInstructions {
const AndroidInstructions({super.key});

@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
L10n.of(context)!.androidInstructionsTitle,
style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
),
Text(
L10n.of(context)!.joinBetaPlayStore,
style: const TextStyle(fontSize: 16),
),
const SizedBox(height: 10.0),
ElevatedButton(
onPressed: () async {
final bool success = await openUrl(AppConfig.playStoreUrl, context);
if (!success) {
await openUrl(AppConfig.androidBetaUrl, context);
}
},
child: Text(L10n.of(context)!.downloadBetaAndroidButton),
),
],
);
}
}
145 changes: 145 additions & 0 deletions lib/pages/beta/beta.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
import 'dart:io' show Platform;

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:future_loading_dialog/future_loading_dialog.dart';
import 'package:go_router/go_router.dart';
import 'package:matrix/matrix.dart';
import 'package:tawkie/config/app_config.dart';
import 'package:tawkie/widgets/matrix.dart';

import 'android_instructions.dart';
import 'ios_instructions.dart';

class BetaJoinPage extends StatelessWidget {
const BetaJoinPage({super.key});

Future<void> joinGroup({
required BuildContext context,
}) async {
final client = Matrix.of(context).client;
const String roomAlias = AppConfig.roomAlias;

try {
if (kDebugMode) {
print('Attempting to join room: $roomAlias');
}

// Get room ID from alias
final roomAliasResult = await client.getRoomIdByAlias(roomAlias);
final roomId = roomAliasResult.roomId;

if (roomId == null) {
final errorMsg = L10n.of(context)!.failedToJoinRoom +
L10n.of(context)!.roomIdNullError +
roomAlias;
if (kDebugMode) {
print(errorMsg);
}
throw Exception(errorMsg);
}

// Check if the user is already a member of the room
final room = client.getRoomById(roomId);
if (room != null && room.membership == Membership.join) {
// Navigate directly to the room
context.go('/rooms/$roomId');
return;
}

final result = await showFutureLoadingDialog<String>(
context: context,
future: () async {
try {
final waitForRoom = client.waitForRoomInSync(roomId, join: true);

await client.joinRoom(roomId);
await waitForRoom;

return roomId;
} catch (e) {
final errorMsg = L10n.of(context)!.failedToJoinRoom + e.toString();
if (kDebugMode) {
print(errorMsg);
}
throw Exception(errorMsg);
}
},
);

if (result.error == null) {
Navigator.of(context).pop();

final joinedRoom = client.getRoomById(result.result!);
if (joinedRoom == null) {
final errorMsg = L10n.of(context)!.failedToJoinRoom +
L10n.of(context)!.roomNotFoundError;
if (kDebugMode) {
print(errorMsg);
}
throw Exception(errorMsg);
}

// Navigate to the room
context.go('/rooms/${result.result!}');
} else {
final errorMsg =
L10n.of(context)!.failedToJoinRoom + result.error.toString();
if (kDebugMode) {
print(errorMsg);
}
final snackBar = SnackBar(content: Text(errorMsg));
ScaffoldMessenger.of(context).showSnackBar(snackBar);
}
} catch (e) {
final errorMsg = L10n.of(context)!.joinBetaError + e.toString();
if (kDebugMode) {
print(errorMsg);
}
final snackBar = SnackBar(content: Text(errorMsg));
ScaffoldMessenger.of(context).showSnackBar(snackBar);
}
}

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(L10n.of(context)!.joinBetaTitle),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: ListView(
children: [
Text(
L10n.of(context)!.betaJoinExplanation,
style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
const SizedBox(height: 20.0),
Text(
L10n.of(context)!.betaJoinBenefit,
style: const TextStyle(fontSize: 16),
),
const SizedBox(height: 20.0),
if (Platform.isIOS) const IOSInstructions(),
if (Platform.isAndroid) const AndroidInstructions(),
const Divider(thickness: 1),
Text(
L10n.of(context)!.joinBetaGroup,
style: const TextStyle(fontSize: 16),
),
const SizedBox(height: 10.0),
ElevatedButton.icon(
onPressed: () async {
await joinGroup(context: context);
},
icon: const Icon(Icons.new_releases),
label: Text(L10n.of(context)!.joinBetaButtonLabel),
),
],
),
),
);
}
}
25 changes: 25 additions & 0 deletions lib/pages/beta/instructions.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:url_launcher/url_launcher.dart';

abstract class BetaInstructions extends StatelessWidget {
const BetaInstructions({super.key});

// Launch url in browser or device app
Future<bool> openUrl(String url, BuildContext context) async {
try {
if (await canLaunchUrl(Uri.parse(url))) {
await launchUrl(Uri.parse(url));
return true;
}
} catch (e) {
if (kDebugMode) {
print('Error to lauch url: $e');
}
final snackBar = SnackBar(content: Text(L10n.of(context)!.tryAgain));
ScaffoldMessenger.of(context).showSnackBar(snackBar);
}
return false;
}
}
44 changes: 44 additions & 0 deletions lib/pages/beta/ios_instructions.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:tawkie/config/app_config.dart';
import 'package:tawkie/pages/beta/instructions.dart';

class IOSInstructions extends BetaInstructions {
const IOSInstructions({super.key});

@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
L10n.of(context)!.iosInstructionsTitle,
style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
),
Text(
L10n.of(context)!.installTestflight,
style: const TextStyle(fontSize: 16),
),
const SizedBox(height: 10.0),
ElevatedButton(
onPressed: () async {
await openUrl(AppConfig.testflightAppUrl, context);
},
child: Text(L10n.of(context)!.downloadTestflightButton),
),
const Divider(thickness: 1),
Text(
L10n.of(context)!.joinBetaTitle,
style: const TextStyle(fontSize: 16),
),
const SizedBox(height: 10.0),
ElevatedButton(
onPressed: () async {
await openUrl(AppConfig.appleBetaUrl, context);
},
child: Text(L10n.of(context)!.downloadBetaIOSButton),
),
],
);
}
}
Loading

0 comments on commit 66f7c70

Please sign in to comment.