mirror of
https://github.com/twonlyapp/twonly-app.git
synced 2026-01-15 15:08:41 +00:00
fix #217
This commit is contained in:
parent
ff96a80373
commit
434945cb54
10 changed files with 117 additions and 30 deletions
70
lib/app.dart
70
lib/app.dart
|
|
@ -1,3 +1,4 @@
|
|||
import 'dart:io';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:twonly/globals.dart';
|
||||
|
|
@ -5,6 +6,7 @@ import 'package:twonly/src/localization/generated/app_localizations.dart';
|
|||
import 'package:twonly/src/providers/connection.provider.dart';
|
||||
import 'package:twonly/src/providers/settings.provider.dart';
|
||||
import 'package:twonly/src/services/api/media_upload.dart';
|
||||
import 'package:twonly/src/utils/misc.dart';
|
||||
import 'package:twonly/src/utils/storage.dart';
|
||||
import 'package:twonly/src/views/onboarding/onboarding.view.dart';
|
||||
import 'package:twonly/src/views/home.view.dart';
|
||||
|
|
@ -12,6 +14,7 @@ import 'package:twonly/src/views/onboarding/register.view.dart';
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||
import 'dart:async';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
// these two callbacks are called on updated to the corresponding database
|
||||
|
||||
|
|
@ -24,6 +27,7 @@ class App extends StatefulWidget {
|
|||
|
||||
class _AppState extends State<App> with WidgetsBindingObserver {
|
||||
bool wasPaused = false;
|
||||
bool appIsOutdated = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
|
|
@ -62,6 +66,12 @@ class _AppState extends State<App> with WidgetsBindingObserver {
|
|||
|
||||
Future initAsync() async {
|
||||
setUserPlan();
|
||||
globalCallbackAppIsOutdated = () async {
|
||||
context.read<CustomChangeProvider>().updateConnectionState(false);
|
||||
setState(() {
|
||||
appIsOutdated = true;
|
||||
});
|
||||
};
|
||||
await apiService.connect(force: true);
|
||||
apiService.listenToNetworkChanges();
|
||||
// call this function so invalid media files are get purged
|
||||
|
|
@ -87,6 +97,7 @@ class _AppState extends State<App> with WidgetsBindingObserver {
|
|||
void dispose() {
|
||||
WidgetsBinding.instance.removeObserver(this);
|
||||
globalCallbackConnectionState = (a) {};
|
||||
globalCallbackAppIsOutdated = () {};
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
|
|
@ -133,8 +144,10 @@ class _AppState extends State<App> with WidgetsBindingObserver {
|
|||
themeMode: context.watch<SettingsChangeProvider>().themeMode,
|
||||
initialRoute: '/',
|
||||
routes: {
|
||||
"/": (context) => AppMainWidget(initialPage: 1),
|
||||
"/chats": (context) => AppMainWidget(initialPage: 0)
|
||||
"/": (context) =>
|
||||
AppMainWidget(initialPage: 1, appIsOutdated: appIsOutdated),
|
||||
"/chats": (context) =>
|
||||
AppMainWidget(initialPage: 0, appIsOutdated: appIsOutdated)
|
||||
},
|
||||
);
|
||||
},
|
||||
|
|
@ -143,8 +156,10 @@ class _AppState extends State<App> with WidgetsBindingObserver {
|
|||
}
|
||||
|
||||
class AppMainWidget extends StatefulWidget {
|
||||
const AppMainWidget({super.key, required this.initialPage});
|
||||
const AppMainWidget(
|
||||
{super.key, required this.initialPage, required this.appIsOutdated});
|
||||
final int initialPage;
|
||||
final bool appIsOutdated;
|
||||
@override
|
||||
State<AppMainWidget> createState() => _AppMainWidgetState();
|
||||
}
|
||||
|
|
@ -187,6 +202,55 @@ class _AppMainWidgetState extends State<AppMainWidget> {
|
|||
);
|
||||
},
|
||||
),
|
||||
if (widget.appIsOutdated)
|
||||
Positioned(
|
||||
top: 60,
|
||||
left: 30,
|
||||
right: 30,
|
||||
child: SafeArea(
|
||||
child: Container(
|
||||
padding: EdgeInsets.symmetric(vertical: 10, horizontal: 8),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.red,
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
Text(
|
||||
context.lang.appOutdated,
|
||||
textAlign: TextAlign.center,
|
||||
softWrap: true,
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodyMedium
|
||||
?.copyWith(color: Colors.white, fontSize: 16),
|
||||
),
|
||||
if (Platform.isAndroid) SizedBox(height: 5),
|
||||
if (Platform.isAndroid)
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
launchUrl(Uri.parse(
|
||||
"https://play.google.com/store/apps/details?id=eu.twonly"));
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
),
|
||||
child: Text(
|
||||
context.lang.appOutdatedBtn,
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodyMedium
|
||||
?.copyWith(color: Colors.white, fontSize: 16),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ bool gIsDemoUser = false;
|
|||
|
||||
// This callback called by the apiProvider
|
||||
Function(bool) globalCallbackConnectionState = (a) {};
|
||||
Function() globalCallbackAppIsOutdated = () {};
|
||||
|
||||
bool globalIsAppInBackground = true;
|
||||
int globalBestFriendUserId = -1;
|
||||
|
|
|
|||
|
|
@ -298,5 +298,7 @@
|
|||
"backupTwonlySaveNow": "Jetzt speichern",
|
||||
"inviteFriends": "Freunde einladen",
|
||||
"inviteFriendsShareBtn": "Teilen",
|
||||
"inviteFriendsShareText": "Wechseln wir zu twonly: {url}"
|
||||
"inviteFriendsShareText": "Wechseln wir zu twonly: {url}",
|
||||
"appOutdated": "Deine Version von twonly ist veraltet.",
|
||||
"appOutdatedBtn": "Jetzt aktualisieren."
|
||||
}
|
||||
|
|
@ -455,5 +455,7 @@
|
|||
"twonlySafeRecoverBtn": "Restore backup",
|
||||
"inviteFriends": "Invite your friends",
|
||||
"inviteFriendsShareBtn": "Share",
|
||||
"inviteFriendsShareText": "Let's switch to twonly: {url}"
|
||||
"inviteFriendsShareText": "Let's switch to twonly: {url}",
|
||||
"appOutdated": "Your version of twonly is out of date.",
|
||||
"appOutdatedBtn": "Update Now"
|
||||
}
|
||||
|
|
@ -1831,6 +1831,18 @@ abstract class AppLocalizations {
|
|||
/// In en, this message translates to:
|
||||
/// **'Let\'s switch to twonly: {url}'**
|
||||
String inviteFriendsShareText(Object url);
|
||||
|
||||
/// No description provided for @appOutdated.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Your version of twonly is out of date.'**
|
||||
String get appOutdated;
|
||||
|
||||
/// No description provided for @appOutdatedBtn.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Update Now'**
|
||||
String get appOutdatedBtn;
|
||||
}
|
||||
|
||||
class _AppLocalizationsDelegate
|
||||
|
|
|
|||
|
|
@ -974,4 +974,10 @@ class AppLocalizationsDe extends AppLocalizations {
|
|||
String inviteFriendsShareText(Object url) {
|
||||
return 'Wechseln wir zu twonly: $url';
|
||||
}
|
||||
|
||||
@override
|
||||
String get appOutdated => 'Deine Version von twonly ist veraltet.';
|
||||
|
||||
@override
|
||||
String get appOutdatedBtn => 'Jetzt aktualisieren.';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -968,4 +968,10 @@ class AppLocalizationsEn extends AppLocalizations {
|
|||
String inviteFriendsShareText(Object url) {
|
||||
return 'Let\'s switch to twonly: $url';
|
||||
}
|
||||
|
||||
@override
|
||||
String get appOutdated => 'Your version of twonly is out of date.';
|
||||
|
||||
@override
|
||||
String get appOutdatedBtn => 'Update Now';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ class ApiService {
|
|||
final String apiHost = (kDebugMode) ? "10.99.0.140:3030" : "api.twonly.eu";
|
||||
final String apiSecure = (kDebugMode) ? "" : "s";
|
||||
|
||||
bool appIsOutdated = false;
|
||||
bool isAuthenticated = false;
|
||||
ApiService();
|
||||
|
||||
|
|
@ -60,6 +61,7 @@ class ApiService {
|
|||
StreamSubscription<List<ConnectivityResult>>? connectivitySubscription;
|
||||
|
||||
Future<bool> _connectTo(String apiUrl) async {
|
||||
if (appIsOutdated) return false;
|
||||
try {
|
||||
var channel = IOWebSocketChannel.connect(
|
||||
Uri.parse(apiUrl),
|
||||
|
|
@ -303,6 +305,13 @@ class ApiService {
|
|||
Result res = asResult(await _waitForResponse(seq));
|
||||
if (res.isError) {
|
||||
Log.error("got error from server: ${res.error}");
|
||||
if (res.error == ErrorCode.AppVersionOutdated) {
|
||||
globalCallbackAppIsOutdated();
|
||||
Log.error("App Version is OUTDATED.");
|
||||
appIsOutdated = true;
|
||||
await close(() {});
|
||||
return Result.error(ErrorCode.InternalError);
|
||||
}
|
||||
if (res.error == ErrorCode.SessionNotAuthenticated) {
|
||||
isAuthenticated = false;
|
||||
if (authenticated) {
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import 'package:twonly/src/utils/storage.dart';
|
|||
|
||||
class SaveToGalleryButton extends StatefulWidget {
|
||||
final Future<Uint8List?> Function() getMergedImage;
|
||||
final String? sendNextMediaToUserName;
|
||||
final bool displayButtonLabel;
|
||||
final File? videoFilePath;
|
||||
final int? mediaUploadId;
|
||||
final bool isLoading;
|
||||
|
|
@ -20,7 +20,7 @@ class SaveToGalleryButton extends StatefulWidget {
|
|||
super.key,
|
||||
required this.getMergedImage,
|
||||
required this.isLoading,
|
||||
this.sendNextMediaToUserName,
|
||||
required this.displayButtonLabel,
|
||||
this.mediaUploadId,
|
||||
this.videoFilePath,
|
||||
});
|
||||
|
|
@ -107,8 +107,8 @@ class SaveToGalleryButtonState extends State<SaveToGalleryButton> {
|
|||
: _imageSaved
|
||||
? Icon(Icons.check)
|
||||
: FaIcon(FontAwesomeIcons.floppyDisk),
|
||||
if (widget.sendNextMediaToUserName == null) SizedBox(width: 10),
|
||||
if (widget.sendNextMediaToUserName == null)
|
||||
if (widget.displayButtonLabel) SizedBox(width: 10),
|
||||
if (widget.displayButtonLabel)
|
||||
Text(_imageSaved
|
||||
? context.lang.shareImagedEditorSavedImage
|
||||
: context.lang.shareImagedEditorSaveImage)
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ import 'dart:io';
|
|||
import 'dart:async';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||
import 'package:twonly/globals.dart';
|
||||
import 'package:twonly/src/model/protobuf/api/websocket/error.pb.dart'
|
||||
show ErrorCode;
|
||||
import 'package:twonly/src/services/api/media_upload.dart';
|
||||
|
|
@ -56,7 +55,6 @@ class ShareImageEditorView extends StatefulWidget {
|
|||
class _ShareImageEditorView extends State<ShareImageEditorView> {
|
||||
bool _isRealTwonly = false;
|
||||
int maxShowTime = gMediaShowInfinite;
|
||||
String? sendNextMediaToUserName;
|
||||
double tabDownPosition = 0;
|
||||
bool sendingOrLoadingImage = true;
|
||||
bool loadingImage = true;
|
||||
|
|
@ -138,15 +136,6 @@ class _ShareImageEditorView extends State<ShareImageEditorView> {
|
|||
setState(() {});
|
||||
}
|
||||
|
||||
Future updateAsync(int userId) async {
|
||||
if (sendNextMediaToUserName != null) return;
|
||||
Contact? contact =
|
||||
await twonlyDB.contactsDao.getContactByUserId(userId).getSingleOrNull();
|
||||
if (contact != null) {
|
||||
sendNextMediaToUserName = getContactDisplayName(contact);
|
||||
}
|
||||
}
|
||||
|
||||
List<Widget> get actionsAtTheRight {
|
||||
if (layers.isNotEmpty &&
|
||||
layers.last.isEditing &&
|
||||
|
|
@ -449,10 +438,6 @@ class _ShareImageEditorView extends State<ShareImageEditorView> {
|
|||
Widget build(BuildContext context) {
|
||||
pixelRatio = MediaQuery.of(context).devicePixelRatio;
|
||||
|
||||
if (widget.sendTo != null) {
|
||||
sendNextMediaToUserName = getContactDisplayName(widget.sendTo!);
|
||||
}
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor:
|
||||
widget.sharedFromGallery ? null : Colors.white.withAlpha(0),
|
||||
|
|
@ -553,11 +538,11 @@ class _ShareImageEditorView extends State<ShareImageEditorView> {
|
|||
getMergedImage: getMergedImage,
|
||||
mediaUploadId: mediaUploadId,
|
||||
videoFilePath: widget.videoFilePath,
|
||||
sendNextMediaToUserName: sendNextMediaToUserName,
|
||||
displayButtonLabel: widget.sendTo == null,
|
||||
isLoading: loadingImage,
|
||||
),
|
||||
if (sendNextMediaToUserName != null) SizedBox(width: 10),
|
||||
if (sendNextMediaToUserName != null)
|
||||
if (widget.sendTo != null) SizedBox(width: 10),
|
||||
if (widget.sendTo != null)
|
||||
OutlinedButton(
|
||||
style: OutlinedButton.styleFrom(
|
||||
iconColor: Theme.of(context).colorScheme.primary,
|
||||
|
|
@ -566,7 +551,7 @@ class _ShareImageEditorView extends State<ShareImageEditorView> {
|
|||
onPressed: pushShareImageView,
|
||||
child: FaIcon(FontAwesomeIcons.userPlus),
|
||||
),
|
||||
SizedBox(width: sendNextMediaToUserName == null ? 20 : 10),
|
||||
SizedBox(width: widget.sendTo == null ? 20 : 10),
|
||||
FilledButton.icon(
|
||||
icon: sendingOrLoadingImage
|
||||
? SizedBox(
|
||||
|
|
@ -589,9 +574,9 @@ class _ShareImageEditorView extends State<ShareImageEditorView> {
|
|||
),
|
||||
),
|
||||
label: Text(
|
||||
(sendNextMediaToUserName == null)
|
||||
(widget.sendTo == null)
|
||||
? context.lang.shareImagedEditorShareWith
|
||||
: sendNextMediaToUserName!,
|
||||
: getContactDisplayName(widget.sendTo!),
|
||||
style: TextStyle(fontSize: 17),
|
||||
),
|
||||
),
|
||||
|
|
|
|||
Loading…
Reference in a new issue