mirror of
https://github.com/venera-app/venera.git
synced 2025-09-27 15:57:25 +00:00
initial commit
This commit is contained in:
92
lib/utils/ext.dart
Normal file
92
lib/utils/ext.dart
Normal file
@@ -0,0 +1,92 @@
|
||||
extension ListExt<T> on List<T>{
|
||||
/// Remove all blank value and return the list.
|
||||
List<T> getNoBlankList(){
|
||||
List<T> newList = [];
|
||||
for(var value in this){
|
||||
if(value.toString() != ""){
|
||||
newList.add(value);
|
||||
}
|
||||
}
|
||||
return newList;
|
||||
}
|
||||
|
||||
T? firstWhereOrNull(bool Function(T element) test){
|
||||
for(var element in this){
|
||||
if(test(element)){
|
||||
return element;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
void addIfNotNull(T? value){
|
||||
if(value != null){
|
||||
add(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension StringExt on String{
|
||||
///Remove all value that would display blank on the screen.
|
||||
String get removeAllBlank => replaceAll("\n", "").replaceAll(" ", "").replaceAll("\t", "");
|
||||
|
||||
/// convert this to a one-element list.
|
||||
List<String> toList() => [this];
|
||||
|
||||
String _nums(){
|
||||
String res = "";
|
||||
for(int i=0; i<length; i++){
|
||||
res += this[i].isNum?this[i]:"";
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
String get nums => _nums();
|
||||
|
||||
String setValueAt(String value, int index){
|
||||
return replaceRange(index, index+1, value);
|
||||
}
|
||||
|
||||
String? subStringOrNull(int start, [int? end]){
|
||||
if(start < 0 || (end != null && end > length)){
|
||||
return null;
|
||||
}
|
||||
return substring(start, end);
|
||||
}
|
||||
|
||||
String replaceLast(String from, String to) {
|
||||
if (isEmpty || from.isEmpty) {
|
||||
return this;
|
||||
}
|
||||
|
||||
final lastIndex = lastIndexOf(from);
|
||||
if (lastIndex == -1) {
|
||||
return this;
|
||||
}
|
||||
|
||||
final before = substring(0, lastIndex);
|
||||
final after = substring(lastIndex + from.length);
|
||||
return '$before$to$after';
|
||||
}
|
||||
|
||||
static bool hasMatch(String? value, String pattern) {
|
||||
return (value == null) ? false : RegExp(pattern).hasMatch(value);
|
||||
}
|
||||
|
||||
bool _isURL(){
|
||||
final regex = RegExp(
|
||||
r'^((http|https|ftp)://)?[\w-]+(\.[\w-]+)+([\w.,@?^=%&:/~+#-|]*[\w@?^=%&/~+#-])?$',
|
||||
caseSensitive: false);
|
||||
return regex.hasMatch(this);
|
||||
}
|
||||
|
||||
bool get isURL => _isURL();
|
||||
|
||||
bool get isNum => double.tryParse(this) != null;
|
||||
}
|
||||
|
||||
class ListOrNull{
|
||||
static List<T>? from<T>(Iterable<dynamic>? i){
|
||||
return i == null ? null : List.from(i);
|
||||
}
|
||||
}
|
140
lib/utils/io.dart
Normal file
140
lib/utils/io.dart
Normal file
@@ -0,0 +1,140 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:file_picker/file_picker.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:venera/foundation/app.dart';
|
||||
import 'package:venera/utils/ext.dart';
|
||||
|
||||
extension FileSystemEntityExt on FileSystemEntity {
|
||||
String get name {
|
||||
var path = this.path;
|
||||
if (path.endsWith('/') || path.endsWith('\\')) {
|
||||
path = path.substring(0, path.length - 1);
|
||||
}
|
||||
|
||||
int i = path.length - 1;
|
||||
|
||||
while (i >= 0 && path[i] != '\\' && path[i] != '/') {
|
||||
i--;
|
||||
}
|
||||
|
||||
return path.substring(i + 1);
|
||||
}
|
||||
|
||||
Future<void> deleteIgnoreError({bool recursive = false}) async {
|
||||
try {
|
||||
await delete(recursive: recursive);
|
||||
} catch (e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension FileExtension on File {
|
||||
String get extension => path.split('.').last;
|
||||
}
|
||||
|
||||
extension DirectoryExtension on Directory {
|
||||
Future<int> get size async {
|
||||
if (!existsSync()) return 0;
|
||||
int total = 0;
|
||||
for (var f in listSync(recursive: true)) {
|
||||
if (FileSystemEntity.typeSync(f.path) == FileSystemEntityType.file) {
|
||||
total += await File(f.path).length();
|
||||
}
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
Directory renameX(String newName) {
|
||||
newName = sanitizeFileName(newName);
|
||||
return renameSync(path.replaceLast(name, newName));
|
||||
}
|
||||
}
|
||||
|
||||
String sanitizeFileName(String fileName) {
|
||||
const maxLength = 255;
|
||||
final invalidChars = RegExp(r'[<>:"/\\|?*]');
|
||||
final sanitizedFileName = fileName.replaceAll(invalidChars, ' ');
|
||||
var trimmedFileName = sanitizedFileName.trim();
|
||||
if (trimmedFileName.isEmpty) {
|
||||
throw Exception('Invalid File Name: Empty length.');
|
||||
}
|
||||
while (true) {
|
||||
final bytes = utf8.encode(trimmedFileName);
|
||||
if (bytes.length > maxLength) {
|
||||
trimmedFileName =
|
||||
trimmedFileName.substring(0, trimmedFileName.length - 1);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return trimmedFileName;
|
||||
}
|
||||
|
||||
/// Copy the **contents** of the source directory to the destination directory.
|
||||
Future<void> copyDirectory(Directory source, Directory destination) async {
|
||||
List<FileSystemEntity> contents = source.listSync();
|
||||
for (FileSystemEntity content in contents) {
|
||||
String newPath = destination.path +
|
||||
Platform.pathSeparator +
|
||||
content.path.split(Platform.pathSeparator).last;
|
||||
|
||||
if (content is File) {
|
||||
content.copySync(newPath);
|
||||
} else if (content is Directory) {
|
||||
Directory newDirectory = Directory(newPath);
|
||||
newDirectory.createSync();
|
||||
copyDirectory(content.absolute, newDirectory.absolute);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String findValidDirectoryName(String path, String directory) {
|
||||
var name = sanitizeFileName(directory);
|
||||
var dir = Directory("$path/$name");
|
||||
var i = 1;
|
||||
while (dir.existsSync()) {
|
||||
name = sanitizeFileName("$directory($i)");
|
||||
dir = Directory("$path/$name");
|
||||
i++;
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
class DirectoryPicker {
|
||||
String? _directory;
|
||||
|
||||
final _methodChannel = const MethodChannel("venera/method_channel");
|
||||
|
||||
Future<Directory?> pickDirectory() async {
|
||||
if(App.isWindows || App.isLinux) {
|
||||
var d = await FilePicker.platform.getDirectoryPath();
|
||||
_directory = d;
|
||||
return d == null ? null : Directory(d);
|
||||
} else if (App.isAndroid) {
|
||||
var d = await _methodChannel.invokeMethod<String?>("getDirectoryPath");
|
||||
_directory = d;
|
||||
return d == null ? null : Directory(d);
|
||||
} else {
|
||||
// ios, macos
|
||||
var d = await _methodChannel.invokeMethod<String?>("getDirectoryPath");
|
||||
_directory = d;
|
||||
return d == null ? null : Directory(d);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> dispose() async {
|
||||
if(_directory == null) {
|
||||
return;
|
||||
}
|
||||
if(App.isAndroid && _directory != null) {
|
||||
return Directory(_directory!).deleteIgnoreError(recursive: true);
|
||||
}
|
||||
if(App.isIOS || App.isMacOS) {
|
||||
await _methodChannel.invokeMethod("stopAccessingSecurityScopedResource");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
43
lib/utils/translations.dart
Normal file
43
lib/utils/translations.dart
Normal file
@@ -0,0 +1,43 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/services.dart';
|
||||
import '../foundation/app.dart';
|
||||
|
||||
extension AppTranslation on String {
|
||||
String _translate() {
|
||||
var locale = App.locale;
|
||||
var key = "${locale.languageCode}_${locale.countryCode}";
|
||||
if (locale.languageCode == "en") {
|
||||
key = "en_US";
|
||||
}
|
||||
return (translations[key]?[this]) ?? this;
|
||||
}
|
||||
|
||||
String get tl => _translate();
|
||||
|
||||
String get tlEN => translations["en_US"]![this] ?? this;
|
||||
|
||||
String tlParams(Map<String, Object> values) {
|
||||
var res = _translate();
|
||||
for (var entry in values.entries) {
|
||||
res = res.replaceFirst("@${entry.key}", entry.value.toString());
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static late final Map<String, Map<String, String>> translations;
|
||||
|
||||
static Future<void> init() async{
|
||||
var data = await rootBundle.load("assets/translation.json");
|
||||
var json = jsonDecode(utf8.decode(data.buffer.asUint8List()));
|
||||
translations = { for (var e in json.entries) e.key : Map<String, String>.from(e.value) };
|
||||
}
|
||||
}
|
||||
|
||||
extension ListTranslation on List<String> {
|
||||
List<String> _translate() {
|
||||
return List.generate(length, (index) => this[index].tl);
|
||||
}
|
||||
|
||||
List<String> get tl => _translate();
|
||||
}
|
Reference in New Issue
Block a user