1110 check app version and prompt user to update (#1215)

* initial work for checking app version

* fix error in version endpoint url

* show dialog on new version available

---------

Co-authored-by: wcjord <32568597+wcjord@users.noreply.github.com>
pull/1544/head
ggurdin 11 months ago committed by GitHub
parent 07f56a7ff6
commit e38c1a08ee
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -4589,5 +4589,11 @@
"createChatAndInviteUsers": "Create chat and invite users",
"updatedNewSpaceDescription": "Spaces allow you to consolidate your chats and build private or public communities.",
"joinWithCode": "Join with code",
"enterCodeToJoin": "Enter code to join"
"enterCodeToJoin": "Enter code to join",
"mandatoryUpdateRequired": "Mandatory Update Required",
"updateAvailable": "Update Available",
"mandatoryUpdateRequiredDesc": "A new version of the app is required to continue. Please update now to proceed.",
"updateAvailableDesc": "A new version of the app is available. Update now for the latest features and improvements!",
"updateNow": "Update Now",
"updateLater": "Later"
}

@ -1,16 +0,0 @@
BASE_API='https://api.staging.pangea.chat/api/v1'
CHOREO_API = "http://localhost:8000/choreo"
FRONTEND_URL='https://app.pangea.chat'
SYNAPSE_URL = 'matrix.staging.pangea.chat'
CHOREO_API_KEY = 'e6fa9fa97031ba0c852efe78457922f278a2fbc109752fe18e465337699e9873'
RC_PROJECT = 'a499dc21'
RC_KEY = 'sk_eVGBdPyInaOfJrKlPBgFVnRynqKJB'
RC_GOOGLE_KEY = 'goog_paQMrzFKGzuWZvcMTPkkvIsifJe'
RC_IOS_KEY = 'appl_DUPqnxuLjkBLzhBPTWeDjqNENuv'
RC_STRIPE_KEY = 'strp_YWZxWUeEfvagiefDNoofinaRCOl'
RC_OFFERING_NAME = 'test'
STRIPE_MANAGEMENT_LINK = 'https://billing.stripe.com/p/login/test_9AQaI8d3O9lmaXe5kk'

@ -156,6 +156,9 @@ abstract class AppConfig {
static String iosPromoCode =
"https://apps.apple.com/redeem?ctx=offercodes&id=1445118630&code=";
static String trialSubscriptionId = "pangea_new_user_trial";
static String androidUpdateURL =
"https://play.google.com/store/apps/details?id=com.talktolearn.chat";
static String iosUpdateURL = "itms-apps://itunes.apple.com/app/id1445118630";
// Pangea#
static void loadFromJson(Map<String, dynamic> json) {

@ -7,6 +7,7 @@ import 'package:fluffychat/config/themes.dart';
import 'package:fluffychat/pages/chat/send_file_dialog.dart';
import 'package:fluffychat/pages/chat_list/chat_list_view.dart';
import 'package:fluffychat/pangea/constants/pangea_room_types.dart';
import 'package:fluffychat/pangea/controllers/app_version_controller.dart';
import 'package:fluffychat/pangea/extensions/client_extension/client_extension.dart';
import 'package:fluffychat/pangea/extensions/pangea_room_extension/pangea_room_extension.dart';
import 'package:fluffychat/pangea/utils/chat_list_handle_space_tap.dart';
@ -570,6 +571,8 @@ class ChatListController extends State<ChatList>
Matrix.of(context).store.getString(_serverStoreNamespace);
Matrix.of(context).backgroundPush?.setupPush();
UpdateNotifier.showUpdateSnackBar(context);
AppVersionController.showAppVersionDialog(context);
}
// Workaround for system UI overlay style not applied on app start

@ -8,4 +8,5 @@ class PLocalKey {
static const String completedActivities = 'completedActivities';
static const String justInputtedCode = 'justInputtedCode';
static const String availableSubscriptionInfo = 'availableSubscriptionInfo';
static const String showedUpdateDialog = 'showedUpdateDialog';
}

@ -132,4 +132,9 @@ class ModelKey {
// room code
static const String joinRule = "join_rule";
static const String accessCode = "access_code";
// app version
static const String latestVersion = "latest_version";
static const String latestBuildNumber = "latest_build_number";
static const String mandatoryUpdate = "mandatory_update";
}

@ -0,0 +1,175 @@
import 'dart:convert';
import 'package:adaptive_dialog/adaptive_dialog.dart';
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/pangea/config/environment.dart';
import 'package:fluffychat/pangea/constants/local.key.dart';
import 'package:fluffychat/pangea/constants/model_keys.dart';
import 'package:fluffychat/pangea/network/requests.dart';
import 'package:fluffychat/pangea/network/urls.dart';
import 'package:fluffychat/utils/platform_infos.dart';
import 'package:fluffychat/widgets/matrix.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:http/http.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:universal_html/html.dart' as html;
import 'package:url_launcher/url_launcher_string.dart';
class AppVersionController {
static Future<AppVersionResponse> _getAppVersion(
String accessToken,
) async {
final packageInfo = await PackageInfo.fromPlatform();
final currentVersion = packageInfo.version;
final currentBuildNumber = packageInfo.buildNumber;
final Requests request = Requests(
choreoApiKey: Environment.choreoApiKey,
accessToken: accessToken,
);
Map<String, dynamic> json = {};
final Response res = await request.post(
url: PApiUrls.appVersion,
body: {
"current_version": currentVersion,
"current_build_number": currentBuildNumber,
},
);
json = jsonDecode(res.body);
return AppVersionResponse.fromJson(json);
}
static Future<void> showAppVersionDialog(BuildContext context) async {
final packageInfo = await PackageInfo.fromPlatform();
final currentVersion = packageInfo.version;
final currentBuildNumber = packageInfo.buildNumber;
final accessToken = MatrixState.pangeaController.userController.accessToken;
final AppVersionResponse resp = await _getAppVersion(accessToken);
final remoteVersion = resp.latestVersion;
final remoteBuildNumber = resp.latestBuildNumber;
final mandatoryUpdate = resp.mandatoryUpdate;
if (currentVersion == remoteVersion &&
currentBuildNumber == remoteBuildNumber) {
return;
}
if (!mandatoryUpdate &&
showedUpdateDialog != null &&
DateTime.now().difference(showedUpdateDialog!) <
const Duration(days: 1)) {
return;
}
final OkCancelResult dialogResponse =
await _showDialog(context, mandatoryUpdate);
if (!mandatoryUpdate && dialogResponse != OkCancelResult.ok) {
await MatrixState.pangeaController.pStoreService.save(
PLocalKey.showedUpdateDialog,
DateTime.now().toIso8601String(),
);
}
if (dialogResponse == OkCancelResult.ok) {
_launchUpdate();
}
}
static Future<OkCancelResult> _showDialog(
BuildContext context,
bool mandatoryUpdate,
) async {
final title = mandatoryUpdate
? L10n.of(context).mandatoryUpdateRequired
: L10n.of(context).updateAvailable;
final message = mandatoryUpdate
? L10n.of(context).mandatoryUpdateRequiredDesc
: L10n.of(context).updateAvailableDesc;
return mandatoryUpdate
? showOkAlertDialog(
context: context,
title: title,
message: message,
canPop: false,
barrierDismissible: false,
okLabel: L10n.of(context).updateNow,
)
: showOkCancelAlertDialog(
context: context,
title: title,
message: message,
canPop: false,
barrierDismissible: false,
okLabel: L10n.of(context).updateNow,
cancelLabel: L10n.of(context).updateLater,
);
}
static Future<void> _launchUpdate() async {
if (kIsWeb) {
html.window.location.reload();
return;
}
final String url = PlatformInfos.isIOS
? AppConfig.iosUpdateURL
: AppConfig.androidUpdateURL;
await launchUrlString(url);
}
static DateTime? get showedUpdateDialog {
final entry = MatrixState.pangeaController.pStoreService
.read(PLocalKey.showedUpdateDialog);
if (entry == null) return null;
try {
return DateTime.parse(entry);
} catch (e) {
return null;
}
}
}
class AppVersionResponse {
final String latestVersion;
final String latestBuildNumber;
final bool mandatoryUpdate;
AppVersionResponse({
required this.latestVersion,
required this.latestBuildNumber,
required this.mandatoryUpdate,
});
factory AppVersionResponse.fromJson(Map<String, dynamic> json) {
if (json[ModelKey.mandatoryUpdate] is! bool) {
throw Exception("mandatory_update is not a boolean");
}
if (json[ModelKey.latestVersion] is! String) {
throw Exception("latest_version is not a string");
}
if (json[ModelKey.latestBuildNumber] is! String) {
throw Exception("latest_build_number is not a string");
}
return AppVersionResponse(
latestVersion: json[ModelKey.latestVersion],
latestBuildNumber: json[ModelKey.latestBuildNumber],
mandatoryUpdate: json[ModelKey.mandatoryUpdate],
);
}
Map<String, dynamic> toJson() {
return {
ModelKey.latestVersion: latestVersion,
ModelKey.latestBuildNumber: latestBuildNumber,
ModelKey.mandatoryUpdate: mandatoryUpdate,
};
}
}

@ -70,4 +70,6 @@ class PApiUrls {
"${PApiUrls.subscriptionEndpoint}/all_products";
static String rcSubscription = "$rcApiV1/subscribers";
static String appVersion = "${PApiUrls.choreoEndpoint}/version";
}

Loading…
Cancel
Save