replace globals with app environment

This commit is contained in:
otsmr 2026-04-21 02:15:31 +02:00
parent 693c74df46
commit d9f9f7645e
15 changed files with 48 additions and 45 deletions

View file

@ -1,17 +1,28 @@
import 'package:camera/camera.dart';
import 'package:flutter/material.dart';
import 'package:path_provider/path_provider.dart';
import 'package:twonly/src/database/twonly.db.dart';
import 'package:twonly/src/model/json/userdata.dart';
import 'package:twonly/src/services/api.service.dart';
import 'package:twonly/src/services/subscription.service.dart';
class AppEnvironment {
static late final String cacheDir;
static late final String supportDir;
static late final List<CameraDescription> cameras;
static Future<void> init() async {
cacheDir = (await getApplicationCacheDirectory()).path;
supportDir = (await getApplicationSupportDirectory()).path;
cameras = await availableCameras();
}
}
late ApiService apiService;
// uses for background notification
late TwonlyDB twonlyDB;
List<CameraDescription> gCameras = <CameraDescription>[];
// Cached UserData in the memory. Every time the user data is changed the `updateUserdata` function is called,
// which will update this global variable. The variable is set in the main.dart and after the user has registered in the register.view.dart
late UserData gUser;
@ -36,8 +47,5 @@ bool globalIsInBackgroundTask = false;
bool globalAllowErrorTrackingViaSentry = false;
bool globalGotMessageFromServer = false;
late String globalApplicationCacheDirectory;
late String globalApplicationSupportDirectory;
final GlobalKey<ScaffoldMessengerState> globalRootScaffoldMessengerKey =
GlobalKey<ScaffoldMessengerState>();

View file

@ -1,11 +1,9 @@
import 'dart:async';
import 'dart:io';
import 'package:camera/camera.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:path_provider/path_provider.dart';
import 'package:provider/provider.dart';
import 'package:sentry_flutter/sentry_flutter.dart';
import 'package:twonly/app.dart';
@ -35,10 +33,7 @@ void main() async {
SentryWidgetsFlutterBinding.ensureInitialized();
await RustLib.init();
globalApplicationCacheDirectory = (await getApplicationCacheDirectory()).path;
globalApplicationSupportDirectory =
(await getApplicationSupportDirectory()).path;
await AppEnvironment.init();
initLogger();
@ -46,8 +41,8 @@ void main() async {
await bridge.initializeTwonlyFlutter(
config: bridge.TwonlyConfig(
databasePath: '$globalApplicationSupportDirectory/twonly.sqlite',
dataDirectory: globalApplicationSupportDirectory,
databasePath: '${AppEnvironment.supportDir}/twonly.sqlite',
dataDirectory: AppEnvironment.supportDir,
),
);
@ -56,7 +51,7 @@ void main() async {
var user = await getUser();
if (Platform.isIOS && user != null) {
final db = File('$globalApplicationSupportDirectory/twonly.sqlite');
final db = File('${AppEnvironment.supportDir}/twonly.sqlite');
if (!db.existsSync()) {
Log.error('[twonly] IOS: App was removed and then reinstalled again...');
await const FlutterSecureStorage().deleteAll();
@ -92,8 +87,6 @@ void main() async {
unawaited(setupPushNotification());
gCameras = await availableCameras();
apiService = ApiService();
twonlyDB = TwonlyDB();

@ -1 +1 @@
Subproject commit 0029f698ea3deb47dedc4ee1f37e5688d1f83f9b
Subproject commit e1ac9e6c476f82819063a8087af4d42acc1167d4

View file

@ -62,9 +62,8 @@ Future<bool> initBackgroundExecution() async {
}
SentryWidgetsFlutterBinding.ensureInitialized();
globalApplicationCacheDirectory = (await getApplicationCacheDirectory()).path;
globalApplicationSupportDirectory =
(await getApplicationSupportDirectory()).path;
AppEnvironment.cacheDir = (await getApplicationCacheDirectory()).path;
AppEnvironment.supportDir = (await getApplicationSupportDirectory()).path;
initLogger();

View file

@ -41,9 +41,9 @@ Future<void> performTwonlySafeBackup({bool force = false}) async {
Log.info('Starting new twonly Backup!');
final baseDir = globalApplicationSupportDirectory;
final backupDir = Directory(join(baseDir, 'backup_twonly_safe/'));
final backupDir = Directory(
join(AppEnvironment.supportDir, 'backup_twonly_safe/'),
);
await backupDir.create(recursive: true);
final backupDatabaseFile = File(join(backupDir.path, 'twonly.backup.sqlite'));
@ -53,7 +53,9 @@ Future<void> performTwonlySafeBackup({bool force = false}) async {
);
// copy database
final originalDatabase = File(join(baseDir, 'twonly.sqlite'));
final originalDatabase = File(
join(AppEnvironment.supportDir, 'twonly.sqlite'),
);
await originalDatabase.copy(backupDatabaseFile.path);
driftRuntimeOptions.dontWarnAboutMultipleDatabases = true;

View file

@ -90,7 +90,7 @@ Future<void> handleBackupData(
);
final originalDatabase = File(
join(globalApplicationSupportDirectory, 'twonly.sqlite'),
join(AppEnvironment.supportDir, 'twonly.sqlite'),
);
await originalDatabase.writeAsBytes(backupContent.twonlyDatabase);

View file

@ -27,7 +27,7 @@ class MediaFileService {
try {
final tempDirectory = MediaFileService.buildDirectoryPath(
'tmp',
globalApplicationSupportDirectory,
AppEnvironment.supportDir,
);
final files = tempDirectory.listSync();
@ -307,7 +307,7 @@ class MediaFileService {
}
final mediaBaseDir = buildDirectoryPath(
directory,
globalApplicationSupportDirectory,
AppEnvironment.supportDir,
);
return File(
join(mediaBaseDir.path, '${mediaFile.mediaId}$namePrefix.$extension'),

View file

@ -37,7 +37,7 @@ Future<void> createPushAvatars({int? forceForUserId}) async {
File avatarPNGFile(int contactId) {
final avatarsDirectory = Directory(
'$globalApplicationCacheDirectory/avatars',
'${AppEnvironment.cacheDir}/avatars',
);
if (!avatarsDirectory.existsSync()) {

View file

@ -8,7 +8,7 @@ Future<T> exclusiveAccess<T>({
required Future<T> Function() action,
required Mutex mutex,
}) async {
final lockFile = File('$globalApplicationSupportDirectory/$lockName.lock');
final lockFile = File('${AppEnvironment.supportDir}/$lockName.lock');
return mutex.protect(() async {
var lockAcquired = false;

View file

@ -5,7 +5,7 @@ import 'package:twonly/src/utils/log.dart';
class KeyValueStore {
static Future<File> _getFilePath(String key) async {
return File('$globalApplicationSupportDirectory/keyvalue/$key.json');
return File('${AppEnvironment.supportDir}/keyvalue/$key.json');
}
static Future<void> delete(String key) async {

View file

@ -72,7 +72,7 @@ class Log {
Future<String> loadLogFile() async {
return _protectFileAccess(() async {
final logFile = File('$globalApplicationSupportDirectory/app.log');
final logFile = File('${AppEnvironment.supportDir}/app.log');
if (logFile.existsSync()) {
return logFile.readAsString();
@ -84,7 +84,7 @@ Future<String> loadLogFile() async {
Future<String> readLast1000Lines() async {
return _protectFileAccess(() async {
final file = File('$globalApplicationSupportDirectory/app.log');
final file = File('${AppEnvironment.supportDir}/app.log');
if (!file.existsSync()) return '';
final all = await file.readAsLines();
final start = all.length > 1000 ? all.length - 1000 : 0;
@ -103,7 +103,7 @@ Future<T> _protectFileAccess<T>(Future<T> Function() action) async {
}
Future<void> _writeLogToFile(LogRecord record) async {
final logFile = File('$globalApplicationSupportDirectory/app.log');
final logFile = File('${AppEnvironment.supportDir}/app.log');
final logMessage =
'${clock.now().toString().split(".")[0]} ${record.level.name} [twonly] ${record.loggerName} > ${record.message}\n';
@ -127,7 +127,7 @@ Future<void> _writeLogToFile(LogRecord record) async {
Future<void> cleanLogFile() async {
return _protectFileAccess(() async {
final logFile = File('$globalApplicationSupportDirectory/app.log');
final logFile = File('${AppEnvironment.supportDir}/app.log');
if (!logFile.existsSync()) {
return;
@ -162,7 +162,7 @@ Future<void> cleanLogFile() async {
Future<bool> deleteLogFile() async {
return _protectFileAccess(() async {
final logFile = File('$globalApplicationSupportDirectory/app.log');
final logFile = File('${AppEnvironment.supportDir}/app.log');
if (logFile.existsSync()) {
await logFile.delete();

View file

@ -592,7 +592,7 @@ class _CameraPreviewViewState extends State<CameraPreviewView> {
@override
Widget build(BuildContext context) {
if (mc.selectedCameraDetails.cameraId >= gCameras.length ||
if (mc.selectedCameraDetails.cameraId >= AppEnvironment.cameras.length ||
mc.cameraController == null) {
return Container();
}

View file

@ -105,16 +105,17 @@ class MainCameraController {
initCameraStarted = true;
var cameraId = sCameraId;
if (cameraId >= gCameras.length) {
if (cameraId >= AppEnvironment.cameras.length) {
Log.warn(
'Trying to select a non existing camera $cameraId >= ${gCameras.length}',
'Trying to select a non existing camera $cameraId >= ${AppEnvironment.cameras.length}',
);
return;
}
if (init) {
for (; cameraId < gCameras.length; cameraId++) {
if (gCameras[cameraId].lensDirection == CameraLensDirection.back) {
for (; cameraId < AppEnvironment.cameras.length; cameraId++) {
if (AppEnvironment.cameras[cameraId].lensDirection ==
CameraLensDirection.back) {
break;
}
}
@ -124,7 +125,7 @@ class MainCameraController {
if (cameraController == null) {
cameraController = CameraController(
gCameras[cameraId],
AppEnvironment.cameras[cameraId],
ResolutionPreset.high,
enableAudio: await Permission.microphone.isGranted,
imageFormatGroup: Platform.isAndroid
@ -150,7 +151,7 @@ class MainCameraController {
selectedCameraDetails.scaleFactor = 1;
await cameraController?.setZoomLevel(1);
await cameraController?.setDescription(gCameras[cameraId]);
await cameraController?.setDescription(AppEnvironment.cameras[cameraId]);
try {
if (!isVideoRecording) {
await cameraController?.startImageStream(_processCameraImage);

View file

@ -51,11 +51,11 @@ class _CameraZoomButtonsState extends State<CameraZoomButtons> {
Future<void> initAsync() async {
showWideAngleZoom = (await widget.controller.getMinZoomLevel()) < 1;
var index = gCameras.indexWhere(
var index = AppEnvironment.cameras.indexWhere(
(t) => t.lensType == CameraLensType.ultraWide,
);
if (index == -1) {
index = gCameras.indexWhere(
index = AppEnvironment.cameras.indexWhere(
(t) => t.lensType == CameraLensType.wide,
);
}

View file

@ -48,7 +48,7 @@ class _ExportMediaViewState extends State<ExportMediaView> {
Directory _mediaFolder() {
final dir = MediaFileService.buildDirectoryPath(
'stored',
globalApplicationSupportDirectory,
AppEnvironment.supportDir,
);
if (!dir.existsSync()) dir.createSync(recursive: true);
return dir;