Skip to content

Commit

Permalink
redirect to app upgrade page when app needs update #1100
Browse files Browse the repository at this point in the history
  • Loading branch information
bibash28 committed Jan 16, 2023
1 parent 91aa3a3 commit e5bfca3
Show file tree
Hide file tree
Showing 8 changed files with 240 additions and 14 deletions.
7 changes: 6 additions & 1 deletion lib/app/shared/enum/status/splash_status.dart
Original file line number Diff line number Diff line change
@@ -1 +1,6 @@
enum SplashStatus { init, routeToPassCode, routeToOnboarding }
enum SplashStatus {
init,
routeToPassCode,
routeToOnboarding,
routeToAppUpdate,
}
1 change: 1 addition & 0 deletions lib/app_upgrade/app_upgrade.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export 'view/app_upgrade_page.dart';
135 changes: 135 additions & 0 deletions lib/app_upgrade/view/app_upgrade_page.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
import 'package:altme/app/app.dart';
import 'package:altme/dashboard/dashboard.dart';
import 'package:altme/l10n/l10n.dart';
import 'package:altme/onboarding/onboarding.dart';
import 'package:altme/splash/splash.dart';
import 'package:altme/theme/theme.dart';
import 'package:altme/wallet/wallet.dart';
import 'package:cryptocurrency_keys/cryptocurrency_keys.dart';
import 'package:file_saver/file_saver.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:secure_storage/secure_storage.dart';

class AppUpgradePage extends StatelessWidget {
const AppUpgradePage({Key? key, required this.storeInfo}) : super(key: key);

final StoreInfo storeInfo;

static Route route({required StoreInfo storeInfo}) => MaterialPageRoute<void>(
builder: (_) => AppUpgradePage(storeInfo: storeInfo),
settings: const RouteSettings(name: '/AppUpgradePage'),
);

@override
Widget build(BuildContext context) {
return AppUpgradeView(storeInfo: storeInfo);
}
}

class AppUpgradeView extends StatelessWidget {
const AppUpgradeView({
Key? key,
required this.storeInfo,
}) : super(key: key);

final StoreInfo storeInfo;

@override
Widget build(BuildContext context) {
final textTheme = Theme.of(context).textTheme;
final l10n = context.l10n;

return WillPopScope(
onWillPop: () async => false,
child: BasePage(
scrollView: false,
padding: const EdgeInsets.symmetric(horizontal: 20),
body: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: [
const SizedBox(height: 20),
Image.asset(
ImageStrings.splashImage,
fit: BoxFit.fitWidth,
height: MediaQuery.of(context).size.longestSide * 0.3,
),
const SizedBox(height: 30),
Text(
'Time to update',
style: textTheme.titleLarge,
),
const SizedBox(height: 20),
Text(
'''We have added lots of features and fixed some bugs to make your experience as much as possible.''',
textAlign: TextAlign.center,
style: textTheme.bodyLarge,
),
const SizedBox(height: 20),
Text(
'''A new version of Altme is avaible! You can now update this app from v${storeInfo.localVersion} to v${storeInfo.storeVersion}.''',
textAlign: TextAlign.center,
style: textTheme.bodyLarge,
),
if (storeInfo.releaseNotes.isNotEmpty) ...[
const SizedBox(height: 10),
TextButton(
onPressed: () {
showDialog<bool>(
context: context,
builder: (context) => InfoDialog(
title: storeInfo.releaseNotes,
button: l10n.ok,
),
);
},
child: Text(
"What's new in v${storeInfo.storeVersion}?",
style: Theme.of(context).textTheme.copyToClipBoard,
),
),
],
const SizedBox(height: 30),
MyGradientButton(
onPressed: () {},
text: 'Update Now',
),
const SizedBox(height: 10),
FutureBuilder<List<CredentialModel>>(
future: CredentialsRepository(getSecureStorage).findAll(),
builder: (context, snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.done:
final credentials = snapshot.data ?? [];

if (credentials.isNotEmpty) {
return TextButton(
onPressed: () {
Navigator.of(context)
.push<void>(BackupCredentialPage.route());
},
child: Text(
'Backup your Credential',
style: Theme.of(context).textTheme.copyToClipBoard,
),
);
} else {
return const SizedBox();
}
case ConnectionState.waiting:
case ConnectionState.none:
case ConnectionState.active:
return const SizedBox();
}
},
),
const SizedBox(height: 10),
],
),
),
),
);
}
}
36 changes: 24 additions & 12 deletions lib/splash/bloclisteners/blocklisteners.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import 'package:altme/app/app.dart';
import 'package:altme/app_upgrade/app_upgrade.dart';
import 'package:altme/connection_bridge/connection_bridge.dart';
import 'package:altme/dashboard/dashboard.dart';
import 'package:altme/l10n/l10n.dart';
Expand All @@ -16,20 +17,31 @@ import 'package:flutter_bloc/flutter_bloc.dart';

final splashBlocListener = BlocListener<SplashCubit, SplashState>(
listener: (BuildContext context, SplashState state) {
if (state.status == SplashStatus.routeToPassCode) {
Navigator.of(context).push<void>(
PinCodePage.route(
isValidCallback: () {
Navigator.of(context).push<void>(DashboardPage.route());
},
),
);
}

if (state.status == SplashStatus.routeToOnboarding) {
Navigator.of(context).push<void>(StarterPage.route());
switch (state.status) {
case SplashStatus.init:
break;
case SplashStatus.routeToPassCode:
Navigator.of(context).push<void>(
PinCodePage.route(
isValidCallback: () {
Navigator.of(context).push<void>(DashboardPage.route());
},
),
);
break;
case SplashStatus.routeToOnboarding:
Navigator.of(context).push<void>(StarterPage.route());
break;
case SplashStatus.routeToAppUpdate:
Navigator.of(context).push<void>(
AppUpgradePage.route(
storeInfo: state.storeInfo,
),
);
break;
}

// TODO(all): remove
// just for next build -> 117 and then we should remove for build -> 118
context.read<AdvanceSettingsCubit>().setState(
Parameters.defaultAdvanceSettingsState,
Expand Down
23 changes: 23 additions & 0 deletions lib/splash/cubit/splash_cubit.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import 'package:altme/wallet/cubit/wallet_cubit.dart';
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:json_annotation/json_annotation.dart';
import 'package:new_version/new_version.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:secure_storage/secure_storage.dart';

Expand All @@ -32,6 +33,28 @@ class SplashCubit extends Cubit<SplashState> {
final DioClient client;

Future<void> initialiseApp() async {
final newVersion = NewVersion(
iOSId: 'io.altme.wallet',
androidId: 'co.altme.alt.me.altme',
);

final VersionStatus? versionStatus = await newVersion.getVersionStatus();

if (versionStatus != null && versionStatus.canUpdate) {
emit(
state.copyWith(
status: SplashStatus.routeToAppUpdate,
storeInfo: StoreInfo(
localVersion: versionStatus.localVersion,
storeVersion: versionStatus.storeVersion,
appStoreLink: versionStatus.appStoreLink,
releaseNotes: versionStatus.releaseNotes ?? '',
),
),
);
return;
}

final bool hasWallet = await isWalletCreated(
secureStorageProvider: secureStorageProvider,
didCubit: didCubit,
Expand Down
42 changes: 42 additions & 0 deletions lib/splash/cubit/splash_state.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ class SplashState extends Equatable {
this.status = SplashStatus.init,
this.versionNumber = '',
this.buildNumber = '',
this.storeInfo = const StoreInfo(),
});

factory SplashState.fromJson(Map<String, dynamic> json) =>
Expand All @@ -14,16 +15,19 @@ class SplashState extends Equatable {
final SplashStatus status;
final String versionNumber;
final String buildNumber;
final StoreInfo storeInfo;

SplashState copyWith({
SplashStatus? status,
String? versionNumber,
String? buildNumber,
StoreInfo? storeInfo,
}) {
return SplashState(
status: status ?? this.status,
versionNumber: versionNumber ?? this.versionNumber,
buildNumber: buildNumber ?? this.buildNumber,
storeInfo: storeInfo ?? this.storeInfo,
);
}

Expand All @@ -32,3 +36,41 @@ class SplashState extends Equatable {
@override
List<Object?> get props => [status, versionNumber, buildNumber];
}

@JsonSerializable()
class StoreInfo extends Equatable {
const StoreInfo({
this.localVersion = '',
this.storeVersion = '',
this.appStoreLink = '',
this.releaseNotes = '',
});

factory StoreInfo.fromJson(Map<String, dynamic> json) =>
_$StoreInfoFromJson(json);

final String localVersion;
final String storeVersion;
final String appStoreLink;
final String releaseNotes;

StoreInfo copyWith({
String? localVersion,
String? storeVersion,
String? appStoreLink,
String? releaseNotes,
}) {
return StoreInfo(
localVersion: localVersion ?? this.localVersion,
storeVersion: storeVersion ?? this.storeVersion,
appStoreLink: appStoreLink ?? this.appStoreLink,
releaseNotes: releaseNotes ?? this.releaseNotes,
);
}

Map<String, dynamic> toJson() => _$StoreInfoToJson(this);

@override
List<Object?> get props =>
[localVersion, storeVersion, appStoreLink, releaseNotes];
}
7 changes: 7 additions & 0 deletions pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -993,6 +993,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.1"
new_version:
dependency: "direct main"
description:
name: new_version
url: "https://pub.dartlang.org"
source: hosted
version: "0.3.1"
nm:
dependency: transitive
description:
Expand Down
3 changes: 2 additions & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: altme
description: AltMe Flutter App
version: 1.8.11+140
version: 1.0.0+100
publish_to: none

environment:
Expand Down Expand Up @@ -69,6 +69,7 @@ dependencies:
logger: ^1.1.0
mobile_scanner: ^3.0.0-beta.1
network_image_mock: ^2.1.0
new_version: ^0.3.1
package_info_plus: ^1.3.0
passbase_flutter: ^2.13.3
path: ^1.8.0
Expand Down

0 comments on commit e5bfca3

Please sign in to comment.