Skip to content

Commit

Permalink
bug fixes and ui updates and app ota feature added
Browse files Browse the repository at this point in the history
  • Loading branch information
nixrajput committed Sep 1, 2022
1 parent 6274a89 commit 3fedaea
Show file tree
Hide file tree
Showing 15 changed files with 626 additions and 32 deletions.
1 change: 1 addition & 0 deletions android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />

<application
android:label="Rippl!"
Expand Down
15 changes: 15 additions & 0 deletions lib/apis/providers/api_provider.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'dart:convert';

import 'package:http/http.dart' as http;
import 'package:social_media_app/constants/secrets.dart';
import 'package:social_media_app/constants/urls.dart';

class ApiProvider {
Expand Down Expand Up @@ -481,4 +482,18 @@ class ApiProvider {

return response;
}

/// App Update ---------------------------------------------------------------
Future<http.Response> getLatestReleaseInfo() async {
final response = await _client.get(
Uri.parse(AppUrls.githubApiUrl + AppUrls.checkAppUpdateEndpoint),
headers: {
"content-type": "application/json",
"authorization": "Bearer ${AppSecrets.githubToken}",
},
);

return response;
}
}
3 changes: 2 additions & 1 deletion lib/constants/strings.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
abstract class StringValues {
static const appName = 'Rippl!';
static const appVersion = '1.0.0';
static const welcome = 'Welcome';
static const to = 'to';
static const hello = 'Hello';
Expand Down Expand Up @@ -200,4 +199,6 @@ abstract class StringValues {
'https://github.com/nixrajput/social-media-app-flutter/releases';
static const appGithubUrl =
'https://github.com/nixrajput/social-media-app-flutter';
static const appUpdateAvailable = 'App update available';
static const appVersion = '1.0.1+01';
}
4 changes: 4 additions & 0 deletions lib/constants/urls.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ abstract class AppUrls {
// Base URL
static const String locationUrl = 'http://ip-api.com/json';
static const String baseUrl = 'https://social-api.nixlab.co.in/api/v1';
static const String githubApiUrl = 'https://api.github.com';

// Endpoints
static const String loginEndpoint = '/login';
Expand Down Expand Up @@ -43,4 +44,7 @@ abstract class AppUrls {
static const String getFollowingEndpoint = '/get-followings';

static const String getNotifications = '/get-notifications';

static const String checkAppUpdateEndpoint =
'/repos/nixrajput/social-media-app-flutter/releases/latest';
}
50 changes: 50 additions & 0 deletions lib/helpers/utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import 'package:social_media_app/constants/strings.dart';
import 'package:social_media_app/constants/styles.dart';
import 'package:social_media_app/extensions/string_extensions.dart';
import 'package:social_media_app/global_widgets/asset_image.dart';
import 'package:social_media_app/global_widgets/primary_outlined_btn.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:video_compress/video_compress.dart';

Expand Down Expand Up @@ -177,6 +178,55 @@ abstract class AppUtils {
);
}

/// Show No Internet Dialog
static void showAppUpdateDialog() {
closeDialog();
Get.dialog<void>(
WillPopScope(
onWillPop: () async => false,
child: Scaffold(
backgroundColor: Colors.black26,
body: Padding(
padding: Dimens.edgeInsets16,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisAlignment: MainAxisAlignment.center,
children: [
NxAssetImage(
imgAsset: AssetValues.error,
width: Dimens.hundred * 2,
height: Dimens.hundred * 2,
),
Dimens.boxHeight8,
Text(
'App update available',
textAlign: TextAlign.center,
style: AppStyles.style24Bold.copyWith(
color: ColorValues.whiteColor,
),
),
NxOutlinedButton(
label: 'Download Latest APK',
borderColor:
Theme.of(Get.context!).textTheme.bodyText1!.color,
padding: Dimens.edgeInsets0_8,
width: Dimens.screenWidth,
height: Dimens.thirtySix,
labelStyle: AppStyles.style14Normal.copyWith(
color: Theme.of(Get.context!).textTheme.bodyText1!.color,
),
onTap: closeDialog,
),
],
),
),
),
),
barrierDismissible: false,
);
}

/// Show BottomSheet
static void showBottomSheet(List<Widget> children, {double? borderRadius}) {
Expand Down
5 changes: 3 additions & 2 deletions lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import 'package:social_media_app/constants/colors.dart';
import 'package:social_media_app/constants/strings.dart';
import 'package:social_media_app/constants/themes.dart';
import 'package:social_media_app/helpers/utils.dart';
import 'package:social_media_app/modules/app_update/app_update_controller.dart';
import 'package:social_media_app/modules/profile/controllers/profile_controller.dart';
import 'package:social_media_app/modules/settings/controllers/login_device_info_controller.dart';
import 'package:social_media_app/routes/app_pages.dart';
Expand All @@ -32,13 +33,13 @@ Future<void> initServices() async {
..put(AppThemeController(), permanent: true)
..put(AuthService(), permanent: true)
..put(ProfileController(), permanent: true)
..put(LoginDeviceInfoController(), permanent: true);
..put(LoginDeviceInfoController(), permanent: true)
..put(AppUpdateController(), permanent: true);

await Get.find<AuthService>().getToken().then((value) async {
Get.find<AuthService>().autoLogout();
if (value.isNotEmpty) {
var hasData = await Get.find<ProfileController>().getProfileDetails();
await LoginDeviceInfoController.find.getLoginDeviceInfo();
if (hasData) {
isLogin = true;
} else {
Expand Down
226 changes: 226 additions & 0 deletions lib/modules/app_update/app_update_controller.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,226 @@
import 'dart:async';
import 'dart:convert';
import 'dart:io';

import 'package:get/get.dart';
import 'package:http/http.dart' as http;
import 'package:r_upgrade/r_upgrade.dart';
import 'package:social_media_app/apis/providers/api_provider.dart';
import 'package:social_media_app/constants/strings.dart';
import 'package:social_media_app/helpers/utils.dart';
import 'package:social_media_app/routes/route_management.dart';

class AppUpdateController extends GetxController {
static AppUpdateController get find => Get.find();

final _apiProvider = ApiProvider(http.Client());

final _isLoading = false.obs;
final _hasUpdate = false.obs;
final _apkDownloadLink = ''.obs;
final _latestVersion = ''.obs;

bool get isLoading => _isLoading.value;

bool get hasUpdate => _hasUpdate.value;

String get apkDownloadLink => _apkDownloadLink.value;

String get latestVersion => _latestVersion.value;

final currentVersion = '1.0.1+01';

@override
onInit() {
super.onInit();
RUpgrade.setDebug(true);
}

Future<void> _checkAppUpdate(bool showLoading) async {
AppUtils.printLog("Check App Update Request");

_isLoading.value = true;
update();

if (showLoading) {
AppUtils.showLoadingDialog();
}

try {
final response = await _apiProvider.getLatestReleaseInfo();

final decodedData = jsonDecode(utf8.decode(response.bodyBytes));

if (response.statusCode == 200) {
String latestVersion = decodedData['tag_name'];
//String latestVersion = 'v1.0.1+02';

if (latestVersion.contains('+')) {
_latestVersion.value = latestVersion.substring(1);
var splitLatestVer = latestVersion.substring(1).split('+');

var latestBuildVersion = splitLatestVer[0];
var latestBuildNumber = int.parse(splitLatestVer[1]);

var splitLatestBuildVersion = latestBuildVersion.split('.');
var latestBuildVer1 = int.parse(splitLatestBuildVersion[0]);
var latestBuildVer2 = int.parse(splitLatestBuildVersion[1]);
var latestBuildVer3 = int.parse(splitLatestBuildVersion[2]);

final currentBuildVersion = currentVersion.split('+')[0];
final currentBuildNumber = int.parse(currentVersion.split('+')[1]);

var splitCurrentBuildVersion = currentBuildVersion.split('.');
var currentBuildVer1 = int.parse(splitCurrentBuildVersion[0]);
var currentBuildVer2 = int.parse(splitCurrentBuildVersion[1]);
var currentBuildVer3 = int.parse(splitCurrentBuildVersion[2]);

if (latestBuildVer1 > currentBuildVer1) {
_hasUpdate.value = true;
} else if (latestBuildVer1 == currentBuildVer1) {
if (latestBuildVer2 > currentBuildVer2) {
_hasUpdate.value = true;
} else if (latestBuildVer2 == currentBuildVer2) {
if (latestBuildVer3 > currentBuildVer3) {
_hasUpdate.value = true;
} else if (latestBuildVer3 == currentBuildVer3) {
if (latestBuildNumber > currentBuildNumber) {
_hasUpdate.value = true;
} else {
_hasUpdate.value = false;
}
} else {
_hasUpdate.value = false;
}
} else {
_hasUpdate.value = false;
}
} else {
_hasUpdate.value = false;
}

if (_hasUpdate.value == true) {
AppUtils.printLog("Update found");
List<dynamic> assets = decodedData['assets'];
var apk =
assets.singleWhere((element) => element['name'] == 'app.apk');

if (apk != null) {
_apkDownloadLink.value = apk['browser_download_url'];
_isLoading.value = false;
update();
if (showLoading) {
AppUtils.closeDialog();
}
RouteManagement.goToAppUpdateView();
}
} else {
if (showLoading) {
AppUtils.closeDialog();
}
_isLoading.value = false;
update();
AppUtils.printLog("No update found");
}
} else {
_isLoading.value = false;
update();
if (showLoading) {
AppUtils.closeDialog();
}
_hasUpdate.value = false;
_apkDownloadLink.value = '';
AppUtils.printLog("No update found");
}
AppUtils.printLog("Check App Update Success");
} else {
if (showLoading) {
AppUtils.closeDialog();
}
_isLoading.value = false;
update();
AppUtils.printLog("Check App Update Error");
AppUtils.printLog(decodedData);
}
} on SocketException {
if (showLoading) {
AppUtils.closeDialog();
}
_isLoading.value = false;
update();
AppUtils.printLog("Check App Update Error");
AppUtils.printLog(StringValues.internetConnError);
AppUtils.showSnackBar(StringValues.internetConnError, StringValues.error);
} on TimeoutException {
if (showLoading) {
AppUtils.closeDialog();
}
_isLoading.value = false;
update();
AppUtils.printLog("Check App Update Error");
AppUtils.printLog(StringValues.connTimedOut);
AppUtils.printLog(StringValues.connTimedOut);
AppUtils.showSnackBar(StringValues.connTimedOut, StringValues.error);
} on FormatException catch (e) {
if (showLoading) {
AppUtils.closeDialog();
}
_isLoading.value = false;
update();
AppUtils.printLog("Check App Update Error");
AppUtils.printLog(StringValues.formatExcError);
AppUtils.printLog(e);
AppUtils.showSnackBar(StringValues.errorOccurred, StringValues.error);
} catch (exc) {
if (showLoading) {
AppUtils.closeDialog();
}
_isLoading.value = false;
update();
AppUtils.printLog("Check App Update Error");
AppUtils.printLog(StringValues.errorOccurred);
AppUtils.printLog(exc);
AppUtils.showSnackBar(StringValues.errorOccurred, StringValues.error);
}
}

Future<void> _downloadAppUpdate() async {
if (_apkDownloadLink.value.isEmpty || _apkDownloadLink.value == '') {
AppUtils.showSnackBar(
'App download link is invalid.',
StringValues.warning,
);
return;
}

_isLoading.value = true;
update();

var id = await RUpgrade.upgrade(
_apkDownloadLink.value,
fileName: 'app-release.apk',
isAutoRequestInstall: true,
notificationStyle: NotificationStyle.none,
useDownloadManager: false,
);

final status = await RUpgrade.getDownloadStatus(id!);
if (status == DownloadStatus.STATUS_SUCCESSFUL) {
await RUpgrade.install(id);
_isLoading.value = false;
update();
} else if (status == DownloadStatus.STATUS_FAILED) {
_isLoading.value = false;
update();
AppUtils.showSnackBar(
'App download error.',
StringValues.error,
);
}
}

Future<void> checkAppUpdate({bool showLoading = true}) async =>
await _checkAppUpdate(showLoading);

Future<void> downloadAppUpdate() async => await _downloadAppUpdate();
}
Loading

0 comments on commit 3fedaea

Please sign in to comment.