This commit is contained in:
problematicconsumer
2023-12-01 12:56:24 +03:30
parent 9c165e178b
commit ed614988a2
181 changed files with 3092 additions and 2341 deletions

View File

@@ -0,0 +1,32 @@
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:hiddify/core/model/environment.dart';
part 'app_info_entity.freezed.dart';
@freezed
class AppInfoEntity with _$AppInfoEntity {
const AppInfoEntity._();
const factory AppInfoEntity({
required String name,
required String version,
required String buildNumber,
required Release release,
required String operatingSystem,
required String operatingSystemVersion,
required Environment environment,
}) = _AppInfoEntity;
String get userAgent =>
"HiddifyNext/$version ($operatingSystem) like ClashMeta v2ray sing-box";
String get presentVersion => environment == Environment.prod
? version
: "$version ${environment.name}";
/// formats app info for sharing
String format() => '''
$name v$version ($buildNumber) [${environment.name}]
${release.name} release
$operatingSystem [$operatingSystemVersion]''';
}

View File

@@ -0,0 +1,13 @@
abstract class Constants {
static const appName = "Hiddify Next";
static const githubUrl = "https://github.com/hiddify/hiddify-next";
static const githubReleasesApiUrl =
"https://api.github.com/repos/hiddify/hiddify-next/releases";
static const githubLatestReleaseUrl =
"https://github.com/hiddify/hiddify-next/releases/latest";
static const appCastUrl =
"https://raw.githubusercontent.com/hiddify/hiddify-next/main/appcast.xml";
static const telegramChannelUrl = "https://t.me/hiddify";
static const privacyPolicyUrl = "https://hiddify.com/en/privacy-policy/";
static const termsAndConditionsUrl = "https://hiddify.com/terms/";
}

View File

@@ -0,0 +1,7 @@
import 'dart:io';
typedef Directories = ({
Directory baseDir,
Directory workingDir,
Directory tempDir
});

View File

@@ -0,0 +1,25 @@
import 'package:dartx/dartx.dart';
enum Environment {
prod,
dev;
static const sentryDSN = String.fromEnvironment("sentry_dsn");
}
enum Release {
general("general"),
googlePlay("google-play");
const Release(this.key);
final String key;
bool get allowCustomUpdateChecker => this == general;
static Release read() =>
Release.values.firstOrNullWhere(
(e) => e.key == const String.fromEnvironment("release"),
) ??
Release.general;
}

View File

@@ -0,0 +1,73 @@
import 'package:dio/dio.dart';
import 'package:hiddify/core/localization/translations.dart';
typedef PresentableError = ({String type, String? message});
mixin Failure {
({String type, String? message}) present(TranslationsEn t);
}
/// failures that are not expected to happen but depending on [error] type might not be relevant (eg network errors)
mixin UnexpectedFailure {
Object? get error;
StackTrace? get stackTrace;
}
/// failures that are expected to happen and should be handled by the app
/// and should be logged, eg missing permissions
mixin ExpectedMeasuredFailure {}
/// failures ignored by analytics service etc.
mixin ExpectedFailure {}
extension ErrorPresenter on TranslationsEn {
PresentableError errorToPair(Object error) => switch (error) {
UnexpectedFailure(error: final nestedErr?) => errorToPair(nestedErr),
Failure() => error.present(this),
DioException() => error.present(this),
_ => (type: failure.unexpected, message: null),
};
PresentableError presentError(
Object error, {
String? action,
}) {
final pair = errorToPair(error);
if (action == null) return pair;
return (
type: action,
message: pair.type + (pair.message == null ? "" : "\n${pair.message!}"),
);
}
String presentShortError(
Object error, {
String? action,
}) {
final pair = errorToPair(error);
if (action == null) return pair.type;
return "$action: ${pair.type}";
}
}
extension DioExceptionPresenter on DioException {
PresentableError present(TranslationsEn t) => switch (type) {
DioExceptionType.connectionTimeout ||
DioExceptionType.sendTimeout ||
DioExceptionType.receiveTimeout =>
(type: t.failure.connection.timeout, message: null),
DioExceptionType.badCertificate => (
type: t.failure.connection.badCertificate,
message: message,
),
DioExceptionType.badResponse => (
type: t.failure.connection.badResponse,
message: message,
),
DioExceptionType.connectionError => (
type: t.failure.connection.connectionError,
message: message,
),
_ => (type: t.failure.connection.unexpected, message: message),
};
}

View File

@@ -0,0 +1,15 @@
import 'package:hiddify/core/localization/translations.dart';
enum Region {
ir,
cn,
ru,
other;
String present(TranslationsEn t) => switch (this) {
ir => t.settings.general.regions.ir,
cn => t.settings.general.regions.cn,
ru => t.settings.general.regions.ru,
other => t.settings.general.regions.other,
};
}