Merge branch 'feat/parameters' into 'main'
Feat/parameters See merge request jscampucci/libu-notube!2
This commit is contained in:
commit
b3e7a4b643
|
|
@ -1,6 +1,6 @@
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<application
|
<application
|
||||||
android:label="notube"
|
android:label="noTube"
|
||||||
android:name="${applicationName}"
|
android:name="${applicationName}"
|
||||||
android:icon="@mipmap/ic_launcher">
|
android:icon="@mipmap/ic_launcher">
|
||||||
<activity
|
<activity
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
<key>CFBundleDevelopmentRegion</key>
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||||
<key>CFBundleDisplayName</key>
|
<key>CFBundleDisplayName</key>
|
||||||
<string>Notube</string>
|
<string>noTube</string>
|
||||||
<key>CFBundleExecutable</key>
|
<key>CFBundleExecutable</key>
|
||||||
<string>$(EXECUTABLE_NAME)</string>
|
<string>$(EXECUTABLE_NAME)</string>
|
||||||
<key>CFBundleIdentifier</key>
|
<key>CFBundleIdentifier</key>
|
||||||
|
|
@ -13,7 +13,7 @@
|
||||||
<key>CFBundleInfoDictionaryVersion</key>
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
<string>6.0</string>
|
<string>6.0</string>
|
||||||
<key>CFBundleName</key>
|
<key>CFBundleName</key>
|
||||||
<string>notube</string>
|
<string>noTube</string>
|
||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>APPL</string>
|
<string>APPL</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ enum Format {
|
||||||
'"18/22/bestvideo[ext=mp4]+bestaudio[ext=m4a]/best[ext=mp4]/best"',
|
'"18/22/bestvideo[ext=mp4]+bestaudio[ext=m4a]/best[ext=mp4]/best"',
|
||||||
this.format = 'MP4',
|
this.format = 'MP4',
|
||||||
this.ffmpegCmd = '',
|
this.ffmpegCmd = '',
|
||||||
this.extension = '',
|
this.extension = 'mp4',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ import 'dart:convert';
|
||||||
|
|
||||||
import 'package:bloc/bloc.dart';
|
import 'package:bloc/bloc.dart';
|
||||||
import 'package:equatable/equatable.dart';
|
import 'package:equatable/equatable.dart';
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:notube/constants.dart';
|
import 'package:notube/constants.dart';
|
||||||
import 'package:notube/models/video.dart';
|
import 'package:notube/models/video.dart';
|
||||||
import 'package:notube/services/download.dart';
|
import 'package:notube/services/download.dart';
|
||||||
|
|
@ -29,6 +28,9 @@ class DlFormCubit extends Cubit<DlFormState> {
|
||||||
|
|
||||||
void parseUrl() async {
|
void parseUrl() async {
|
||||||
dlService = await DLServices.init();
|
dlService = await DLServices.init();
|
||||||
|
if (state.url.isEmpty) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
var shellStream = await dlService.analyseUrl(state.url);
|
var shellStream = await dlService.analyseUrl(state.url);
|
||||||
|
|
||||||
shellStream.listen((line) {
|
shellStream.listen((line) {
|
||||||
|
|
@ -43,7 +45,8 @@ class DlFormCubit extends Cubit<DlFormState> {
|
||||||
var video = Video.fromJson(videoTmp);
|
var video = Video.fromJson(videoTmp);
|
||||||
videos.add(video.copyWith(
|
videos.add(video.copyWith(
|
||||||
format: state.format,
|
format: state.format,
|
||||||
filename: '${video.id}_${state.format.format}'));
|
filename: '${video.id}_${state.format.format}',
|
||||||
|
playlistTitle: playlistTitle));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
var video = Video.fromJson(dataInfos);
|
var video = Video.fromJson(dataInfos);
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,7 @@ class DlForm extends StatelessWidget {
|
||||||
DropdownFormat(),
|
DropdownFormat(),
|
||||||
SubmitButton(),
|
SubmitButton(),
|
||||||
]),
|
]),
|
||||||
DebugDlFormState(),
|
//DebugDlFormState(),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ class DropdownFormat extends StatelessWidget {
|
||||||
onChanged: (String? value) {
|
onChanged: (String? value) {
|
||||||
var format =
|
var format =
|
||||||
Format.values.firstWhere((element) => element.format == value);
|
Format.values.firstWhere((element) => element.format == value);
|
||||||
context.read<DlFormCubit>().setFormat(format!);
|
context.read<DlFormCubit>().setFormat(format);
|
||||||
},
|
},
|
||||||
underline: Container(),
|
underline: Container(),
|
||||||
items: Format.values.map<DropdownMenuItem<String>>((Format format) {
|
items: Format.values.map<DropdownMenuItem<String>>((Format format) {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:flutter/rendering.dart';
|
||||||
import 'package:notube/constants.dart';
|
import 'package:notube/constants.dart';
|
||||||
import 'package:notube/models/video.dart';
|
import 'package:notube/models/video.dart';
|
||||||
import 'package:notube/videoList/cubit/videos_cubit.dart';
|
import 'package:notube/videoList/cubit/videos_cubit.dart';
|
||||||
|
|
@ -35,23 +37,27 @@ class _SubmitButtonState extends State<SubmitButton> {
|
||||||
constraints: BoxConstraints.tightFor(width: 200),
|
constraints: BoxConstraints.tightFor(width: 200),
|
||||||
child: MouseRegion(
|
child: MouseRegion(
|
||||||
cursor: SystemMouseCursors.click,
|
cursor: SystemMouseCursors.click,
|
||||||
|
onHover: (PointerHoverEvent event) {
|
||||||
|
setState(() => isHovering = true);
|
||||||
|
},
|
||||||
|
onExit: (PointerExitEvent event) {
|
||||||
|
setState(() => isHovering = false);
|
||||||
|
},
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
context.read<DlFormCubit>().parseUrl();
|
context.read<DlFormCubit>().parseUrl();
|
||||||
},
|
},
|
||||||
child: InkWell(
|
child: Container(
|
||||||
onHover: (hovering) {
|
padding: const EdgeInsets.symmetric(vertical: 14),
|
||||||
debugPrint('Hovering: $hovering');
|
decoration: BoxDecoration(
|
||||||
setState(() => isHovering = hovering);
|
color: isHovering ? colorDarkRed : colorMainRed,
|
||||||
},
|
borderRadius: BorderRadius.only(
|
||||||
child: Container(
|
topRight: Radius.circular(3),
|
||||||
padding: const EdgeInsets.symmetric(vertical: 14),
|
bottomRight: Radius.circular(3),
|
||||||
decoration: BoxDecoration(
|
)),
|
||||||
color: isHovering ? colorDarkRed : colorMainRed,
|
child: const Text('Ok', textAlign: TextAlign.center).tr(),
|
||||||
),
|
),
|
||||||
child: const Text('Ok', textAlign: TextAlign.center).tr(),
|
)),
|
||||||
),
|
|
||||||
))),
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,25 +11,34 @@ class UrlTextField extends StatelessWidget {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Flexible(
|
return Flexible(
|
||||||
child: TextFormField(
|
child: Container(
|
||||||
decoration: InputDecoration(
|
decoration: BoxDecoration(
|
||||||
border: InputBorder.none,
|
color: colorBackgroundBlack,
|
||||||
hintText: 'search_url'.tr(),
|
borderRadius: BorderRadius.only(
|
||||||
filled: true,
|
topLeft: Radius.circular(3),
|
||||||
fillColor: colorBackgroundBlack,
|
bottomLeft: Radius.circular(3),
|
||||||
contentPadding: EdgeInsets.symmetric(
|
|
||||||
horizontal: 20,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
validator: (value) {
|
child: TextFormField(
|
||||||
if (value == null || value.isEmpty) {
|
decoration: InputDecoration(
|
||||||
return 'Please enter some text';
|
border: InputBorder.none,
|
||||||
}
|
hintText: 'search_url'.tr(),
|
||||||
return null;
|
filled: true,
|
||||||
},
|
fillColor: Colors.transparent,
|
||||||
onChanged: (newUrl) {
|
contentPadding: EdgeInsets.symmetric(
|
||||||
context.read<DlFormCubit>().setUrl(newUrl);
|
horizontal: 20,
|
||||||
},
|
),
|
||||||
|
),
|
||||||
|
validator: (value) {
|
||||||
|
if (value == null || value.isEmpty) {
|
||||||
|
return 'Please enter some text';
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
onChanged: (newUrl) {
|
||||||
|
context.read<DlFormCubit>().setUrl(newUrl);
|
||||||
|
},
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
|
import 'package:notube/screens/settings.dart';
|
||||||
import 'package:notube/wrapper.dart';
|
import 'package:notube/wrapper.dart';
|
||||||
import 'package:notube/constants.dart';
|
import 'package:notube/constants.dart';
|
||||||
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
import 'package:window_manager/window_manager.dart';
|
import 'package:window_manager/window_manager.dart';
|
||||||
import 'package:upgrader/upgrader.dart';
|
import 'package:upgrader/upgrader.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
|
@ -15,7 +17,7 @@ void main() async {
|
||||||
WindowOptions windowOptions = WindowOptions(
|
WindowOptions windowOptions = WindowOptions(
|
||||||
size: Size(800, 600),
|
size: Size(800, 600),
|
||||||
minimumSize: Size(320, 400),
|
minimumSize: Size(320, 400),
|
||||||
title: 'NoTube',
|
title: 'noTube',
|
||||||
);
|
);
|
||||||
windowManager.waitUntilReadyToShow(windowOptions, () async {
|
windowManager.waitUntilReadyToShow(windowOptions, () async {
|
||||||
await windowManager.setIcon('assets/images/icon.png');
|
await windowManager.setIcon('assets/images/icon.png');
|
||||||
|
|
@ -63,9 +65,13 @@ class _NoTubeAppState extends State<NoTubeApp> {
|
||||||
localizationsDelegates: context.localizationDelegates,
|
localizationsDelegates: context.localizationDelegates,
|
||||||
supportedLocales: context.supportedLocales,
|
supportedLocales: context.supportedLocales,
|
||||||
locale: context.locale,
|
locale: context.locale,
|
||||||
home: BlocProvider(
|
initialRoute: '/',
|
||||||
create: (context) => VideosCubit(),
|
routes: {
|
||||||
child: UpgradeAlert(upgrader: upgrader, child: const Wrapper())),
|
'/': (context) => BlocProvider(
|
||||||
|
create: (context) => VideosCubit(),
|
||||||
|
child: UpgradeAlert(upgrader: upgrader, child: const Wrapper())),
|
||||||
|
'/settings': (context) => Settings(),
|
||||||
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ class Video extends Equatable {
|
||||||
this.uploader = '',
|
this.uploader = '',
|
||||||
this.uploadDate = '',
|
this.uploadDate = '',
|
||||||
this.filename = '',
|
this.filename = '',
|
||||||
|
this.playlistTitle = '',
|
||||||
});
|
});
|
||||||
|
|
||||||
final String id;
|
final String id;
|
||||||
|
|
@ -33,6 +34,7 @@ class Video extends Equatable {
|
||||||
final String uploader;
|
final String uploader;
|
||||||
final String uploadDate;
|
final String uploadDate;
|
||||||
final String filename;
|
final String filename;
|
||||||
|
final String playlistTitle;
|
||||||
|
|
||||||
factory Video.fromJson(Map<String, dynamic> json) {
|
factory Video.fromJson(Map<String, dynamic> json) {
|
||||||
return Video(
|
return Video(
|
||||||
|
|
@ -63,6 +65,7 @@ class Video extends Equatable {
|
||||||
String? uploader,
|
String? uploader,
|
||||||
String? uploadDate,
|
String? uploadDate,
|
||||||
String? filename,
|
String? filename,
|
||||||
|
String? playlistTitle,
|
||||||
}) {
|
}) {
|
||||||
return Video(
|
return Video(
|
||||||
id: id ?? this.id,
|
id: id ?? this.id,
|
||||||
|
|
@ -78,6 +81,7 @@ class Video extends Equatable {
|
||||||
uploader: uploader ?? this.uploader,
|
uploader: uploader ?? this.uploader,
|
||||||
uploadDate: uploadDate ?? this.uploadDate,
|
uploadDate: uploadDate ?? this.uploadDate,
|
||||||
filename: filename ?? this.filename,
|
filename: filename ?? this.filename,
|
||||||
|
playlistTitle: playlistTitle ?? this.playlistTitle,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -95,5 +99,6 @@ class Video extends Equatable {
|
||||||
url,
|
url,
|
||||||
isParsed,
|
isParsed,
|
||||||
filename,
|
filename,
|
||||||
|
playlistTitle,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,16 @@ class Home extends StatelessWidget {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text('home').tr(),
|
title: Text('home').tr(),
|
||||||
|
actions: [
|
||||||
|
SizedBox(
|
||||||
|
width: 50,
|
||||||
|
child: IconButton(
|
||||||
|
icon: Icon(Icons.settings),
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.pushNamed(context, '/settings');
|
||||||
|
},
|
||||||
|
))
|
||||||
|
],
|
||||||
),
|
),
|
||||||
body: LayoutBuilder(builder:
|
body: LayoutBuilder(builder:
|
||||||
(BuildContext context, BoxConstraints viewportConstraints) {
|
(BuildContext context, BoxConstraints viewportConstraints) {
|
||||||
|
|
@ -64,10 +74,3 @@ class Home extends StatelessWidget {
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
SingleChildScrollView(
|
|
||||||
child: ConstrainedBox(
|
|
||||||
constraints: BoxConstraints(
|
|
||||||
minHeight: viewportConstraints.maxHeight),
|
|
||||||
child:
|
|
||||||
*/
|
|
||||||
|
|
@ -0,0 +1,115 @@
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:downloadsfolder/downloadsfolder.dart';
|
||||||
|
import 'package:file_picker/file_picker.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
|
import 'package:filesystem_picker/filesystem_picker.dart';
|
||||||
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
|
||||||
|
class Settings extends StatefulWidget {
|
||||||
|
Settings({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<Settings> createState() => _SettingsState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _SettingsState extends State<Settings> {
|
||||||
|
late Directory downloadFolder;
|
||||||
|
late SharedPreferences prefs;
|
||||||
|
|
||||||
|
Future<String> _init() async {
|
||||||
|
prefs = await SharedPreferences.getInstance();
|
||||||
|
Directory defaultDownloadDirectory = await getDownloadDirectory();
|
||||||
|
downloadFolder = Directory(
|
||||||
|
prefs.getString('downloadFolder') ?? defaultDownloadDirectory.path);
|
||||||
|
return 'ok';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: Text('settings').tr(),
|
||||||
|
),
|
||||||
|
body: FutureBuilder<String>(
|
||||||
|
future: _init(),
|
||||||
|
builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
|
||||||
|
if (snapshot.connectionState == ConnectionState.waiting) {
|
||||||
|
return CircularProgressIndicator();
|
||||||
|
} else if (snapshot.hasError) {
|
||||||
|
return Center(child: Text('Error: ${snapshot.error}'));
|
||||||
|
} else if (snapshot.hasData) {
|
||||||
|
return LayoutBuilder(builder:
|
||||||
|
(BuildContext context, BoxConstraints viewportConstraints) {
|
||||||
|
return viewportConstraints.maxHeight < double.infinity
|
||||||
|
? Center(
|
||||||
|
child: Container(
|
||||||
|
constraints: viewportConstraints,
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
SizedBox(height: 10),
|
||||||
|
Text('settings').tr(),
|
||||||
|
SizedBox(height: 10),
|
||||||
|
Flexible(
|
||||||
|
child: ListView(
|
||||||
|
children: [
|
||||||
|
ListTile(
|
||||||
|
title: Text('download_folder').tr(),
|
||||||
|
subtitle: Text(downloadFolder.path),
|
||||||
|
trailing: IconButton(
|
||||||
|
icon: Icon(Icons.folder),
|
||||||
|
onPressed: () async {
|
||||||
|
String? selectedDirectory =
|
||||||
|
await FilePicker.platform
|
||||||
|
.getDirectoryPath();
|
||||||
|
|
||||||
|
if (selectedDirectory != null) {
|
||||||
|
prefs.setString('downloadFolder',
|
||||||
|
selectedDirectory);
|
||||||
|
setState(() {
|
||||||
|
downloadFolder =
|
||||||
|
Directory(selectedDirectory);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
ListTile(
|
||||||
|
title: Text('language').tr(),
|
||||||
|
subtitle:
|
||||||
|
Text(context.locale.toString()).tr(),
|
||||||
|
trailing: DropdownButton(
|
||||||
|
items: context.supportedLocales
|
||||||
|
.map((locale) {
|
||||||
|
return DropdownMenuItem(
|
||||||
|
value: locale.toString(),
|
||||||
|
child: Text(locale.toString()).tr(),
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
value: context.locale.toString(),
|
||||||
|
onChanged: (String? value) => {
|
||||||
|
if (value != null)
|
||||||
|
{
|
||||||
|
context.setLocale(Locale(
|
||||||
|
value.split("_")[0],
|
||||||
|
value.split("_")[1])),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: CircularProgressIndicator();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return Center(child: Text('No data'));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,5 +2,10 @@
|
||||||
"test": "EN_test",
|
"test": "EN_test",
|
||||||
"home": "EN_home",
|
"home": "EN_home",
|
||||||
"home_intro": "EN_home_intro",
|
"home_intro": "EN_home_intro",
|
||||||
"search_url": "EN_search_url"
|
"search_url": "EN_search_url",
|
||||||
|
"settings": "EN_Settings",
|
||||||
|
"download_folder": "Download folder",
|
||||||
|
"en_US": "English",
|
||||||
|
"fr_FR": "French",
|
||||||
|
"Ok": "OK"
|
||||||
}
|
}
|
||||||
|
|
@ -2,5 +2,10 @@
|
||||||
"test": "Test",
|
"test": "Test",
|
||||||
"home": "Accueil",
|
"home": "Accueil",
|
||||||
"home_intro": "Saisissez l'url d'une video et laissez la magie opérer!",
|
"home_intro": "Saisissez l'url d'une video et laissez la magie opérer!",
|
||||||
"search_url": "Url"
|
"search_url": "Url",
|
||||||
|
"settings": "Paramètres",
|
||||||
|
"download_folder": "Dossier de téléchargement",
|
||||||
|
"en_US": "Anglais",
|
||||||
|
"fr_FR": "Français",
|
||||||
|
"Ok": "OK"
|
||||||
}
|
}
|
||||||
|
|
@ -91,9 +91,28 @@ class VideosCubit extends Cubit<VideosState> {
|
||||||
final tmpFile =
|
final tmpFile =
|
||||||
File('temp/${video.filename}_done.${video.format.extension}');
|
File('temp/${video.filename}_done.${video.format.extension}');
|
||||||
|
|
||||||
|
var playlistTitle = video.playlistTitle;
|
||||||
|
await Directory('${downloadDirectory.path}/$playlistTitle')
|
||||||
|
.create(recursive: true)
|
||||||
|
.catchError((e) => debugPrint('Error creating directory: $e'));
|
||||||
|
debugPrint('Playlist title: $playlistTitle');
|
||||||
|
if (playlistTitle.isNotEmpty && playlistTitle != '') {
|
||||||
|
cleanTitle = playlistTitle + '/' + cleanTitle;
|
||||||
|
}
|
||||||
|
|
||||||
final newFile = File(
|
final newFile = File(
|
||||||
'${downloadDirectory.path}/${cleanTitle}.${video.format.extension}');
|
'${downloadDirectory.path}/$cleanTitle.${video.format.extension}');
|
||||||
await tmpFile.rename(newFile.path);
|
|
||||||
|
var isMoved = false;
|
||||||
|
while (!isMoved) {
|
||||||
|
try {
|
||||||
|
await tmpFile.rename(newFile.path);
|
||||||
|
isMoved = true;
|
||||||
|
} on FileSystemException catch (e) {
|
||||||
|
debugPrint('Error moving file: $e');
|
||||||
|
await Future.delayed(Duration(seconds: 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
changeStatus(video, 'done');
|
changeStatus(video, 'done');
|
||||||
debugPrint('File moved to ${newFile.path}');
|
debugPrint('File moved to ${newFile.path}');
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ project(runner LANGUAGES CXX)
|
||||||
|
|
||||||
# The name of the executable created for the application. Change this to change
|
# The name of the executable created for the application. Change this to change
|
||||||
# the on-disk name of your application.
|
# the on-disk name of your application.
|
||||||
set(BINARY_NAME "notube")
|
set(BINARY_NAME "noTube")
|
||||||
# The unique GTK application identifier for this application. See:
|
# The unique GTK application identifier for this application. See:
|
||||||
# https://wiki.gnome.org/HowDoI/ChooseApplicationID
|
# https://wiki.gnome.org/HowDoI/ChooseApplicationID
|
||||||
set(APPLICATION_ID "com.example.notube")
|
set(APPLICATION_ID "com.example.notube")
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
// 'flutter create' template.
|
// 'flutter create' template.
|
||||||
|
|
||||||
// The application's name. By default this is also the title of the Flutter window.
|
// The application's name. By default this is also the title of the Flutter window.
|
||||||
PRODUCT_NAME = notube
|
PRODUCT_NAME = noTube
|
||||||
|
|
||||||
// The application's bundle identifier
|
// The application's bundle identifier
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.example.notube
|
PRODUCT_BUNDLE_IDENTIFIER = com.example.notube
|
||||||
|
|
|
||||||
48
pubspec.lock
48
pubspec.lock
|
|
@ -57,6 +57,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.18.0"
|
version: "1.18.0"
|
||||||
|
cross_file:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: cross_file
|
||||||
|
sha256: "55d7b444feb71301ef6b8838dbc1ae02e63dd48c8773f3810ff53bb1e2945b32"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.3.4+1"
|
||||||
crypto:
|
crypto:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -169,6 +177,22 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "7.0.0"
|
version: "7.0.0"
|
||||||
|
file_picker:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: file_picker
|
||||||
|
sha256: "824f5b9f389bfc4dddac3dea76cd70c51092d9dff0b2ece7ef4f53db8547d258"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "8.0.6"
|
||||||
|
filesystem_picker:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: filesystem_picker
|
||||||
|
sha256: cc2bfe7e5a4ce21afd5b1b03824c0e6e5386a981ed6cce7bda062b1af805cf62
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "4.1.0"
|
||||||
flutter:
|
flutter:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description: flutter
|
description: flutter
|
||||||
|
|
@ -203,6 +227,14 @@ packages:
|
||||||
description: flutter
|
description: flutter
|
||||||
source: sdk
|
source: sdk
|
||||||
version: "0.0.0"
|
version: "0.0.0"
|
||||||
|
flutter_plugin_android_lifecycle:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: flutter_plugin_android_lifecycle
|
||||||
|
sha256: c6b0b4c05c458e1c01ad9bcc14041dd7b1f6783d487be4386f793f47a8a4d03e
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.20"
|
||||||
flutter_redux:
|
flutter_redux:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|
@ -301,6 +333,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.1"
|
version: "2.1.1"
|
||||||
|
logger:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: logger
|
||||||
|
sha256: af05cc8714f356fd1f3888fb6741cbe9fbe25cdb6eedbab80e1a6db21047d4a4
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.3.0"
|
||||||
matcher:
|
matcher:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -525,6 +565,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.4.0"
|
version: "0.4.0"
|
||||||
|
rename:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: rename
|
||||||
|
sha256: "6ef5daf4b11130e71d93630cfb70725e5a35b19039739cfcd2b272c834ba25fe"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.0.2"
|
||||||
screen_retriever:
|
screen_retriever:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
name: notube
|
name: notube
|
||||||
description: NoTube
|
description: noTube
|
||||||
|
|
||||||
publish_to: "none" # Remove this line if you wish to publish to pub.dev
|
publish_to: "none" # Remove this line if you wish to publish to pub.dev
|
||||||
|
|
||||||
version: 0.0.1+1
|
version: 0.0.18
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ">=3.0.0 <4.0.0"
|
sdk: ">=3.0.0 <4.0.0"
|
||||||
|
|
@ -30,6 +30,9 @@ dependencies:
|
||||||
bloc: ^8.1.4
|
bloc: ^8.1.4
|
||||||
shared_preferences: ^2.2.3
|
shared_preferences: ^2.2.3
|
||||||
downloadsfolder: ^1.1.0
|
downloadsfolder: ^1.1.0
|
||||||
|
filesystem_picker: ^4.1.0
|
||||||
|
file_picker: ^8.0.6
|
||||||
|
rename: ^3.0.2
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev,
|
||||||
FlutterWindow window(project);
|
FlutterWindow window(project);
|
||||||
Win32Window::Point origin(10, 10);
|
Win32Window::Point origin(10, 10);
|
||||||
Win32Window::Size size(1280, 720);
|
Win32Window::Size size(1280, 720);
|
||||||
if (!window.Create(L"notube", origin, size)) {
|
if (!window.Create(L"noTube", origin, size)) {
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
window.SetQuitOnClose(true);
|
window.SetQuitOnClose(true);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue