feat(file_viewer): implement file view handler
This commit is contained in:
parent
add5442607
commit
16a82b62d1
11 changed files with 243 additions and 138 deletions
|
@ -1,107 +1,108 @@
|
|||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="io.ente.photos">
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="io.ente.photos">
|
||||
<application android:name="${applicationName}"
|
||||
android:label="@string/app_name"
|
||||
android:icon="@mipmap/launcher_icon"
|
||||
android:usesCleartextTraffic="true"
|
||||
android:requestLegacyExternalStorage="true"
|
||||
android:allowBackup="false"
|
||||
android:fullBackupContent="false"
|
||||
android:largeHeap="true">
|
||||
android:label="@string/app_name"
|
||||
android:icon="@mipmap/launcher_icon"
|
||||
android:usesCleartextTraffic="true"
|
||||
android:requestLegacyExternalStorage="true"
|
||||
android:allowBackup="false"
|
||||
android:fullBackupContent="false"
|
||||
android:largeHeap="true">
|
||||
|
||||
<activity android:name=".MainActivity" android:launchMode="singleTop"
|
||||
android:theme="@style/LaunchTheme"
|
||||
android:exported="true"
|
||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
||||
android:hardwareAccelerated="true"
|
||||
android:windowSoftInputMode="adjustResize">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
<!-- <intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<data android:mimeType="image/*" />
|
||||
<data android:mimeType="video/*" />
|
||||
</intent-filter> -->
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.PICK" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<data android:mimeType="image/*" />
|
||||
<data android:mimeType="video/*" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.GET_CONTENT" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.OPENABLE" />
|
||||
<data android:mimeType="image/*" />
|
||||
<data android:mimeType="video/*" />
|
||||
</intent-filter>
|
||||
|
||||
<!-- file provider to share files having a file:// URI -->
|
||||
android:theme="@style/LaunchTheme"
|
||||
android:exported="true"
|
||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
||||
android:hardwareAccelerated="true"
|
||||
android:windowSoftInputMode="adjustResize">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<data android:mimeType="image/*" />
|
||||
<data android:mimeType="video/*" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.PICK" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<data android:mimeType="image/*" />
|
||||
<data android:mimeType="video/*" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.GET_CONTENT" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.OPENABLE" />
|
||||
<data android:mimeType="image/*" />
|
||||
<data android:mimeType="video/*" />
|
||||
</intent-filter>
|
||||
|
||||
<!--Filter to support sharing images into our app-->
|
||||
<!-- file provider to share files having a file:// URI -->
|
||||
|
||||
<!--Filter
|
||||
to support sharing images into our app-->
|
||||
<intent-filter android:label="@string/backup">
|
||||
<action android:name="android.intent.action.SEND"/>
|
||||
<category android:name="android.intent.category.DEFAULT"/>
|
||||
<data android:mimeType="image/*"/>
|
||||
<action android:name="android.intent.action.SEND" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<data android:mimeType="image/*" />
|
||||
</intent-filter>
|
||||
|
||||
<intent-filter android:label="@string/backup">
|
||||
<action android:name="android.intent.action.SEND_MULTIPLE"/>
|
||||
<category android:name="android.intent.category.DEFAULT"/>
|
||||
<data android:mimeType="image/*"/>
|
||||
<action android:name="android.intent.action.SEND_MULTIPLE" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<data android:mimeType="image/*" />
|
||||
</intent-filter>
|
||||
|
||||
<intent-filter android:label="@string/backup">
|
||||
<action android:name="android.intent.action.SEND"/>
|
||||
<category android:name="android.intent.category.DEFAULT"/>
|
||||
<data android:mimeType="video/*"/>
|
||||
<action android:name="android.intent.action.SEND" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<data android:mimeType="video/*" />
|
||||
</intent-filter>
|
||||
|
||||
<intent-filter android:label="@string/backup">
|
||||
<action android:name="android.intent.action.SEND_MULTIPLE"/>
|
||||
<category android:name="android.intent.category.DEFAULT"/>
|
||||
<data android:mimeType="video/*"/>
|
||||
<action android:name="android.intent.action.SEND_MULTIPLE" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<data android:mimeType="video/*" />
|
||||
</intent-filter>
|
||||
|
||||
</activity>
|
||||
|
||||
<!-- Don't delete the meta-data below.
|
||||
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
|
||||
<meta-data android:name="flutterEmbedding" android:value="2"/>
|
||||
<meta-data android:name="flutterEmbedding" android:value="2" />
|
||||
<meta-data android:name="asset_statements"
|
||||
android:resource="@string/asset_statements"/>
|
||||
android:resource="@string/asset_statements" />
|
||||
<meta-data android:name="io.sentry.dsn"
|
||||
android:value="https://2235e5c99219488ea93da34b9ac1cb68@sentry.ente.io/4"/>
|
||||
android:value="https://2235e5c99219488ea93da34b9ac1cb68@sentry.ente.io/4" />
|
||||
<meta-data android:name="firebase_analytics_collection_deactivated"
|
||||
android:value="true"/>
|
||||
android:value="true" />
|
||||
</application>
|
||||
|
||||
<!-- Android 11: https://developer.android.com/preview/privacy/package-visibility -->
|
||||
<!-- https://developer.android.com/training/package-visibility/use-cases -->
|
||||
<queries>
|
||||
<intent>
|
||||
<action android:name="android.intent.action.SENDTO"/>
|
||||
<data android:scheme="mailto"/>
|
||||
<action android:name="android.intent.action.SENDTO" />
|
||||
<data android:scheme="mailto" />
|
||||
</intent>
|
||||
</queries>
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
<uses-permission android:name="android.permission.MANAGE_MEDIA"/>
|
||||
<uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION"/>
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.MANAGE_MEDIA" />
|
||||
<uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION" />
|
||||
<uses-permission
|
||||
android:name="android.permission.READ_MEDIA_IMAGES"/> <!-- If you want to read images-->
|
||||
android:name="android.permission.READ_MEDIA_IMAGES" /> <!-- If you want to read images-->
|
||||
<uses-permission
|
||||
android:name="android.permission.READ_MEDIA_VIDEO"/> <!-- If you want to read videos-->
|
||||
android:name="android.permission.READ_MEDIA_VIDEO" /> <!-- If you want to read videos-->
|
||||
<uses-permission
|
||||
android:name="android.permission.READ_EXTERNAL_STORAGE"
|
||||
android:maxSdkVersion="32"/>
|
||||
android:name="android.permission.READ_EXTERNAL_STORAGE"
|
||||
android:maxSdkVersion="32" />
|
||||
<uses-permission
|
||||
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
|
||||
android:maxSdkVersion="29"
|
||||
tools:ignore="ScopedStorage"/>
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
||||
<uses-permission android:name="com.android.vending.BILLING"/>
|
||||
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
|
||||
android:maxSdkVersion="29"
|
||||
tools:ignore="ScopedStorage" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="com.android.vending.BILLING" />
|
||||
</manifest>
|
69
lib/app.dart
69
lib/app.dart
|
@ -4,16 +4,16 @@ import 'package:adaptive_theme/adaptive_theme.dart';
|
|||
import 'package:background_fetch/background_fetch.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_easyloading/flutter_easyloading.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:media_extension/media_extension.dart';
|
||||
import 'package:media_extension/media_extension_action_types.dart';
|
||||
import 'package:photos/ente_theme_data.dart';
|
||||
import 'package:photos/services/app_lifecycle_service.dart';
|
||||
import 'package:photos/services/sync_service.dart';
|
||||
import 'package:photos/ui/home_widget.dart';
|
||||
import "package:photos/ui/viewer/actions/file_viewer.dart";
|
||||
import "package:photos/utils/intent_util.dart";
|
||||
|
||||
class EnteApp extends StatefulWidget {
|
||||
final Future<void> Function(String) runBackgroundTask;
|
||||
|
@ -31,63 +31,44 @@ class EnteApp extends StatefulWidget {
|
|||
|
||||
class _EnteAppState extends State<EnteApp> with WidgetsBindingObserver {
|
||||
final _logger = Logger("EnteAppState");
|
||||
final _mediaExtensionPlugin = MediaExtension();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_logger.info('init App');
|
||||
super.initState();
|
||||
setupIntentAction();
|
||||
WidgetsBinding.instance.addObserver(this);
|
||||
}
|
||||
|
||||
Future<bool> initIntentAction() async {
|
||||
if (!Platform.isAndroid) {
|
||||
AppLifecycleService.instance.setIntentAction(IntentAction.main);
|
||||
return true;
|
||||
}
|
||||
IntentAction intentAction = IntentAction.main;
|
||||
try {
|
||||
final actionResult = await _mediaExtensionPlugin.getIntentAction();
|
||||
intentAction = actionResult.action!;
|
||||
} on PlatformException {
|
||||
intentAction = IntentAction.main;
|
||||
} catch (error) {
|
||||
_logger.info(error);
|
||||
intentAction = IntentAction.main;
|
||||
}
|
||||
if (intentAction == IntentAction.main) {
|
||||
void setupIntentAction() async {
|
||||
final mediaExtentionAction = await initIntentAction();
|
||||
AppLifecycleService.instance.setMediaExtensionAction(mediaExtentionAction);
|
||||
if (mediaExtentionAction.action == IntentAction.main) {
|
||||
_configureBackgroundFetch();
|
||||
}
|
||||
AppLifecycleService.instance.setIntentAction(intentAction);
|
||||
return true;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (Platform.isAndroid || kDebugMode) {
|
||||
return FutureBuilder(
|
||||
future: initIntentAction(),
|
||||
builder: (BuildContext context, AsyncSnapshot<bool> snapshot) {
|
||||
return snapshot.data != null && snapshot.data == true
|
||||
? AdaptiveTheme(
|
||||
light: lightThemeData,
|
||||
dark: darkThemeData,
|
||||
initial: AdaptiveThemeMode.system,
|
||||
builder: (lightTheme, dartTheme) => MaterialApp(
|
||||
title: "ente",
|
||||
themeMode: ThemeMode.system,
|
||||
theme: lightTheme,
|
||||
darkTheme: dartTheme,
|
||||
home: const HomeWidget(),
|
||||
debugShowCheckedModeBanner: false,
|
||||
builder: EasyLoading.init(),
|
||||
supportedLocales: AppLocalizations.supportedLocales,
|
||||
localizationsDelegates:
|
||||
AppLocalizations.localizationsDelegates,
|
||||
),
|
||||
)
|
||||
: Container();
|
||||
},
|
||||
return AdaptiveTheme(
|
||||
light: lightThemeData,
|
||||
dark: darkThemeData,
|
||||
initial: AdaptiveThemeMode.system,
|
||||
builder: (lightTheme, dartTheme) => MaterialApp(
|
||||
title: "ente",
|
||||
themeMode: ThemeMode.system,
|
||||
theme: lightTheme,
|
||||
darkTheme: dartTheme,
|
||||
home: AppLifecycleService.instance.mediaExtensionAction.action ==
|
||||
IntentAction.view
|
||||
? const FileViewer()
|
||||
: const HomeWidget(),
|
||||
debugShowCheckedModeBanner: false,
|
||||
builder: EasyLoading.init(),
|
||||
supportedLocales: AppLocalizations.supportedLocales,
|
||||
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
return MaterialApp(
|
||||
|
|
|
@ -5,15 +5,17 @@ class AppLifecycleService {
|
|||
final _logger = Logger("AppLifecycleService");
|
||||
|
||||
bool isForeground = false;
|
||||
IntentAction intentAction = IntentAction.main;
|
||||
MediaExtentionAction mediaExtensionAction =
|
||||
MediaExtentionAction(action: IntentAction.main);
|
||||
|
||||
static final AppLifecycleService instance =
|
||||
AppLifecycleService._privateConstructor();
|
||||
|
||||
AppLifecycleService._privateConstructor();
|
||||
|
||||
void setIntentAction(IntentAction intentAction) {
|
||||
this.intentAction = intentAction;
|
||||
void setMediaExtensionAction(MediaExtentionAction mediaExtensionAction) {
|
||||
_logger.info("App invoked via ${mediaExtensionAction.action}");
|
||||
this.mediaExtensionAction = mediaExtensionAction;
|
||||
}
|
||||
|
||||
void onAppInForeground(String reason) {
|
||||
|
|
|
@ -457,8 +457,11 @@ class _CreateCollectionSheetState extends State<CreateCollectionSheet> {
|
|||
}
|
||||
|
||||
Future<bool> _restoreFilesToCollection(int toCollectionID) async {
|
||||
final dialog = createProgressDialog(context, "Restoring files...",
|
||||
isDismissible: true);
|
||||
final dialog = createProgressDialog(
|
||||
context,
|
||||
"Restoring files...",
|
||||
isDismissible: true,
|
||||
);
|
||||
await dialog.show();
|
||||
try {
|
||||
await CollectionsService.instance
|
||||
|
|
|
@ -264,7 +264,7 @@ class _HomeWidgetState extends State<HomeWidget> {
|
|||
_logger.info("Building home_Widget with tab $_selectedTabIndex");
|
||||
bool isSettingsOpen = false;
|
||||
final enableDrawer = LocalSyncService.instance.hasCompletedFirstImport();
|
||||
|
||||
final action = AppLifecycleService.instance.mediaExtensionAction.action;
|
||||
return UserDetailsStateWidget(
|
||||
child: WillPopScope(
|
||||
child: Scaffold(
|
||||
|
@ -297,9 +297,7 @@ class _HomeWidgetState extends State<HomeWidget> {
|
|||
Navigator.pop(context);
|
||||
return false;
|
||||
}
|
||||
if (Platform.isAndroid &&
|
||||
AppLifecycleService.instance.intentAction ==
|
||||
IntentAction.main) {
|
||||
if (Platform.isAndroid && action == IntentAction.main) {
|
||||
MoveToBackground.moveTaskToBack();
|
||||
return false;
|
||||
} else {
|
||||
|
|
|
@ -311,7 +311,6 @@ class _LazyLoadingGridViewState extends State<LazyLoadingGridView> {
|
|||
bool? _shouldRender;
|
||||
int? _currentUserID;
|
||||
late StreamSubscription<ClearSelectionsEvent> _clearSelectionsEvent;
|
||||
final _mediaExtensionPlugin = MediaExtension();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
|
@ -426,16 +425,18 @@ class _LazyLoadingGridViewState extends State<LazyLoadingGridView> {
|
|||
if (widget.selectedFiles.files.isNotEmpty) {
|
||||
_selectFile(file);
|
||||
} else {
|
||||
if (AppLifecycleService.instance.intentAction == IntentAction.pick) {
|
||||
if (AppLifecycleService.instance.mediaExtensionAction.action ==
|
||||
IntentAction.pick) {
|
||||
final ioFile = await getFile(file);
|
||||
_mediaExtensionPlugin.setResult("file://${ioFile!.path}");
|
||||
MediaExtension().setResult("file://${ioFile!.path}");
|
||||
} else {
|
||||
_routeToDetailPage(file, context);
|
||||
}
|
||||
}
|
||||
},
|
||||
onLongPress: () {
|
||||
if (AppLifecycleService.instance.intentAction == IntentAction.main) {
|
||||
if (AppLifecycleService.instance.mediaExtensionAction.action ==
|
||||
IntentAction.main) {
|
||||
HapticFeedback.lightImpact();
|
||||
_selectFile(file);
|
||||
}
|
||||
|
|
|
@ -100,8 +100,9 @@ class _DeleteEmptyAlbumsState extends State<DeleteEmptyAlbums> {
|
|||
"${collections.length}";
|
||||
try {
|
||||
await CollectionsService.instance.trashEmptyCollection(
|
||||
collections[i].collection,
|
||||
isBulkDelete: true);
|
||||
collections[i].collection,
|
||||
isBulkDelete: true,
|
||||
);
|
||||
} catch (_) {
|
||||
failedCount++;
|
||||
}
|
||||
|
|
104
lib/ui/viewer/actions/file_viewer.dart
Normal file
104
lib/ui/viewer/actions/file_viewer.dart
Normal file
|
@ -0,0 +1,104 @@
|
|||
import 'dart:convert';
|
||||
|
||||
import "package:chewie/chewie.dart";
|
||||
import "package:flutter/material.dart";
|
||||
import "package:flutter/services.dart";
|
||||
import "package:logging/logging.dart";
|
||||
import "package:media_extension/media_extension_action_types.dart";
|
||||
import "package:photo_view/photo_view.dart";
|
||||
import "package:photos/services/app_lifecycle_service.dart";
|
||||
|
||||
import "package:video_player/video_player.dart";
|
||||
|
||||
class FileViewer extends StatefulWidget {
|
||||
const FileViewer({super.key});
|
||||
|
||||
@override
|
||||
State<StatefulWidget> createState() {
|
||||
return FileViewerState();
|
||||
}
|
||||
}
|
||||
|
||||
class FileViewerState extends State<FileViewer> {
|
||||
final action = AppLifecycleService.instance.mediaExtensionAction;
|
||||
ChewieController? controller;
|
||||
VideoPlayerController? videoController;
|
||||
final Logger _logger = Logger("FileViewer");
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
if (action.type == MediaType.video) {
|
||||
initController();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
videoController?.dispose();
|
||||
controller?.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void initController() async {
|
||||
videoController = VideoPlayerController.contentUri(
|
||||
Uri.parse(action.data!),
|
||||
);
|
||||
controller = ChewieController(
|
||||
videoPlayerController: videoController!,
|
||||
autoInitialize: true,
|
||||
aspectRatio: 16 / 9,
|
||||
autoPlay: true,
|
||||
looping: true,
|
||||
showOptions: false,
|
||||
materialProgressColors: ChewieProgressColors(
|
||||
playedColor: const Color.fromRGBO(45, 194, 98, 1.0),
|
||||
handleColor: Colors.white,
|
||||
bufferedColor: Colors.white,
|
||||
),
|
||||
);
|
||||
controller!.addListener(() {
|
||||
if (!controller!.isFullScreen) {
|
||||
SystemChrome.setPreferredOrientations(
|
||||
[DeviceOrientation.portraitUp],
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
leading: IconButton(
|
||||
onPressed: () {
|
||||
SystemChannels.platform.invokeMethod('SystemNavigator.pop');
|
||||
},
|
||||
icon: const Icon(Icons.arrow_back),
|
||||
),
|
||||
),
|
||||
body: Column(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Center(
|
||||
child: (() {
|
||||
if (action.type == MediaType.image) {
|
||||
return PhotoView(
|
||||
imageProvider: MemoryImage(base64Decode(action.data!)),
|
||||
);
|
||||
} else if (action.type == MediaType.video) {
|
||||
return controller != null
|
||||
? Chewie(controller: controller!)
|
||||
: const CircularProgressIndicator();
|
||||
} else {
|
||||
_logger.severe('unsupported file type ${action.type}');
|
||||
return const Icon(Icons.error);
|
||||
}
|
||||
})(),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
16
lib/utils/intent_util.dart
Normal file
16
lib/utils/intent_util.dart
Normal file
|
@ -0,0 +1,16 @@
|
|||
import "package:flutter/services.dart";
|
||||
import "package:media_extension/media_extension.dart";
|
||||
import "package:media_extension/media_extension_action_types.dart";
|
||||
|
||||
Future<MediaExtentionAction> initIntentAction() async {
|
||||
final mediaExtensionPlugin = MediaExtension();
|
||||
MediaExtentionAction mediaExtensionAction;
|
||||
try {
|
||||
mediaExtensionAction = await mediaExtensionPlugin.getIntentAction();
|
||||
} on PlatformException {
|
||||
mediaExtensionAction = MediaExtentionAction(action: IntentAction.main);
|
||||
} catch (error) {
|
||||
mediaExtensionAction = MediaExtentionAction(action: IntentAction.main);
|
||||
}
|
||||
return mediaExtensionAction;
|
||||
}
|
|
@ -76,7 +76,7 @@ dependencies:
|
|||
local_auth: ^1.1.5
|
||||
logging: ^1.0.1
|
||||
lottie: ^1.2.2
|
||||
media_extension: ^1.0.0
|
||||
media_extension: ^1.0.1
|
||||
modal_bottom_sheet: ^3.0.0-pre
|
||||
motionphoto:
|
||||
git: "https://github.com/ente-io/motionphoto.git"
|
||||
|
|
14
run.sh
14
run.sh
|
@ -2,14 +2,12 @@
|
|||
|
||||
FLUTTER_RUN="flutter run --flavor dev "
|
||||
|
||||
if [ ! -z "$1" ]
|
||||
then
|
||||
SUPPLIED_ENV_FILE="$1"
|
||||
while IFS= read -r line
|
||||
do
|
||||
FLUTTER_RUN="$FLUTTER_RUN --dart-define $line"
|
||||
SUPPLIED_ENV_FILE=".env"
|
||||
while IFS= read -r line
|
||||
do
|
||||
FLUTTER_RUN="$FLUTTER_RUN --dart-define $line"
|
||||
|
||||
done < "$SUPPLIED_ENV_FILE"
|
||||
|
||||
done < "$SUPPLIED_ENV_FILE"
|
||||
fi
|
||||
echo "Running: $FLUTTER_RUN"
|
||||
$FLUTTER_RUN
|
||||
|
|
Loading…
Add table
Reference in a new issue