Init repo

This commit is contained in:
PartyDonut 2024-09-15 14:12:28 +02:00
commit 764b6034e3
566 changed files with 212335 additions and 0 deletions

View file

@ -0,0 +1,117 @@
import 'dart:convert';
import 'dart:developer';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:fladder/util/custom_color_themes.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
part 'client_settings_model.freezed.dart';
part 'client_settings_model.g.dart';
@freezed
class ClientSettingsModel with _$ClientSettingsModel {
factory ClientSettingsModel({
String? syncPath,
@Default(Vector2(x: 0, y: 0)) Vector2 position,
@Default(Vector2(x: 1280, y: 720)) Vector2 size,
@Default(Duration(seconds: 30)) Duration? timeOut,
Duration? nextUpDateCutoff,
@Default(ThemeMode.system) ThemeMode themeMode,
ColorThemes? themeColor,
@Default(false) bool amoledBlack,
@Default(false) bool blurPlaceHolders,
@Default(false) bool blurUpcomingEpisodes,
@LocaleConvert() Locale? selectedLocale,
@Default(true) bool enableMediaKeys,
@Default(1.0) double posterSize,
@Default(false) bool pinchPosterZoom,
@Default(false) bool mouseDragSupport,
int? libraryPageSize,
}) = _ClientSettingsModel;
factory ClientSettingsModel.fromJson(Map<String, dynamic> json) => _$ClientSettingsModelFromJson(json);
}
class LocaleConvert implements JsonConverter<Locale?, String?> {
const LocaleConvert();
@override
Locale? fromJson(String? json) {
if (json == null) return null;
final parts = json.split('_');
if (parts.length == 1) {
return Locale(parts[0]);
} else if (parts.length == 2) {
return Locale(parts[0], parts[1]);
} else {
log("Invalid Locale format");
return null;
}
}
@override
String? toJson(Locale? object) {
if (object == null) return null;
if (object.countryCode == null || object.countryCode?.isEmpty == true) {
return object.languageCode;
}
return '${object.languageCode}_${object.countryCode}';
}
}
class Vector2 {
final double x;
final double y;
const Vector2({
required this.x,
required this.y,
});
Vector2 copyWith({
double? x,
double? y,
}) {
return Vector2(
x: x ?? this.x,
y: y ?? this.y,
);
}
Map<String, dynamic> toMap() {
return <String, dynamic>{
'x': x,
'y': y,
};
}
factory Vector2.fromMap(Map<String, dynamic> map) {
return Vector2(
x: map['x'] as double,
y: map['y'] as double,
);
}
String toJson() => json.encode(toMap());
factory Vector2.fromJson(String source) => Vector2.fromMap(json.decode(source) as Map<String, dynamic>);
factory Vector2.fromSize(Size size) => Vector2(x: size.width, y: size.height);
@override
String toString() => 'Vector2(x: $x, y: $y)';
@override
bool operator ==(covariant Vector2 other) {
if (identical(this, other)) return true;
return other.x == x && other.y == y;
}
@override
int get hashCode => x.hashCode ^ y.hashCode;
static fromPosition(Offset windowPosition) => Vector2(x: windowPosition.dx, y: windowPosition.dy);
}

View file

@ -0,0 +1,526 @@
// coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
part of 'client_settings_model.dart';
// **************************************************************************
// FreezedGenerator
// **************************************************************************
T _$identity<T>(T value) => value;
final _privateConstructorUsedError = UnsupportedError(
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models');
ClientSettingsModel _$ClientSettingsModelFromJson(Map<String, dynamic> json) {
return _ClientSettingsModel.fromJson(json);
}
/// @nodoc
mixin _$ClientSettingsModel {
String? get syncPath => throw _privateConstructorUsedError;
Vector2 get position => throw _privateConstructorUsedError;
Vector2 get size => throw _privateConstructorUsedError;
Duration? get timeOut => throw _privateConstructorUsedError;
Duration? get nextUpDateCutoff => throw _privateConstructorUsedError;
ThemeMode get themeMode => throw _privateConstructorUsedError;
ColorThemes? get themeColor => throw _privateConstructorUsedError;
bool get amoledBlack => throw _privateConstructorUsedError;
bool get blurPlaceHolders => throw _privateConstructorUsedError;
bool get blurUpcomingEpisodes => throw _privateConstructorUsedError;
@LocaleConvert()
Locale? get selectedLocale => throw _privateConstructorUsedError;
bool get enableMediaKeys => throw _privateConstructorUsedError;
double get posterSize => throw _privateConstructorUsedError;
bool get pinchPosterZoom => throw _privateConstructorUsedError;
bool get mouseDragSupport => throw _privateConstructorUsedError;
int? get libraryPageSize => throw _privateConstructorUsedError;
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
@JsonKey(ignore: true)
$ClientSettingsModelCopyWith<ClientSettingsModel> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $ClientSettingsModelCopyWith<$Res> {
factory $ClientSettingsModelCopyWith(
ClientSettingsModel value, $Res Function(ClientSettingsModel) then) =
_$ClientSettingsModelCopyWithImpl<$Res, ClientSettingsModel>;
@useResult
$Res call(
{String? syncPath,
Vector2 position,
Vector2 size,
Duration? timeOut,
Duration? nextUpDateCutoff,
ThemeMode themeMode,
ColorThemes? themeColor,
bool amoledBlack,
bool blurPlaceHolders,
bool blurUpcomingEpisodes,
@LocaleConvert() Locale? selectedLocale,
bool enableMediaKeys,
double posterSize,
bool pinchPosterZoom,
bool mouseDragSupport,
int? libraryPageSize});
}
/// @nodoc
class _$ClientSettingsModelCopyWithImpl<$Res, $Val extends ClientSettingsModel>
implements $ClientSettingsModelCopyWith<$Res> {
_$ClientSettingsModelCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
@pragma('vm:prefer-inline')
@override
$Res call({
Object? syncPath = freezed,
Object? position = null,
Object? size = null,
Object? timeOut = freezed,
Object? nextUpDateCutoff = freezed,
Object? themeMode = null,
Object? themeColor = freezed,
Object? amoledBlack = null,
Object? blurPlaceHolders = null,
Object? blurUpcomingEpisodes = null,
Object? selectedLocale = freezed,
Object? enableMediaKeys = null,
Object? posterSize = null,
Object? pinchPosterZoom = null,
Object? mouseDragSupport = null,
Object? libraryPageSize = freezed,
}) {
return _then(_value.copyWith(
syncPath: freezed == syncPath
? _value.syncPath
: syncPath // ignore: cast_nullable_to_non_nullable
as String?,
position: null == position
? _value.position
: position // ignore: cast_nullable_to_non_nullable
as Vector2,
size: null == size
? _value.size
: size // ignore: cast_nullable_to_non_nullable
as Vector2,
timeOut: freezed == timeOut
? _value.timeOut
: timeOut // ignore: cast_nullable_to_non_nullable
as Duration?,
nextUpDateCutoff: freezed == nextUpDateCutoff
? _value.nextUpDateCutoff
: nextUpDateCutoff // ignore: cast_nullable_to_non_nullable
as Duration?,
themeMode: null == themeMode
? _value.themeMode
: themeMode // ignore: cast_nullable_to_non_nullable
as ThemeMode,
themeColor: freezed == themeColor
? _value.themeColor
: themeColor // ignore: cast_nullable_to_non_nullable
as ColorThemes?,
amoledBlack: null == amoledBlack
? _value.amoledBlack
: amoledBlack // ignore: cast_nullable_to_non_nullable
as bool,
blurPlaceHolders: null == blurPlaceHolders
? _value.blurPlaceHolders
: blurPlaceHolders // ignore: cast_nullable_to_non_nullable
as bool,
blurUpcomingEpisodes: null == blurUpcomingEpisodes
? _value.blurUpcomingEpisodes
: blurUpcomingEpisodes // ignore: cast_nullable_to_non_nullable
as bool,
selectedLocale: freezed == selectedLocale
? _value.selectedLocale
: selectedLocale // ignore: cast_nullable_to_non_nullable
as Locale?,
enableMediaKeys: null == enableMediaKeys
? _value.enableMediaKeys
: enableMediaKeys // ignore: cast_nullable_to_non_nullable
as bool,
posterSize: null == posterSize
? _value.posterSize
: posterSize // ignore: cast_nullable_to_non_nullable
as double,
pinchPosterZoom: null == pinchPosterZoom
? _value.pinchPosterZoom
: pinchPosterZoom // ignore: cast_nullable_to_non_nullable
as bool,
mouseDragSupport: null == mouseDragSupport
? _value.mouseDragSupport
: mouseDragSupport // ignore: cast_nullable_to_non_nullable
as bool,
libraryPageSize: freezed == libraryPageSize
? _value.libraryPageSize
: libraryPageSize // ignore: cast_nullable_to_non_nullable
as int?,
) as $Val);
}
}
/// @nodoc
abstract class _$$ClientSettingsModelImplCopyWith<$Res>
implements $ClientSettingsModelCopyWith<$Res> {
factory _$$ClientSettingsModelImplCopyWith(_$ClientSettingsModelImpl value,
$Res Function(_$ClientSettingsModelImpl) then) =
__$$ClientSettingsModelImplCopyWithImpl<$Res>;
@override
@useResult
$Res call(
{String? syncPath,
Vector2 position,
Vector2 size,
Duration? timeOut,
Duration? nextUpDateCutoff,
ThemeMode themeMode,
ColorThemes? themeColor,
bool amoledBlack,
bool blurPlaceHolders,
bool blurUpcomingEpisodes,
@LocaleConvert() Locale? selectedLocale,
bool enableMediaKeys,
double posterSize,
bool pinchPosterZoom,
bool mouseDragSupport,
int? libraryPageSize});
}
/// @nodoc
class __$$ClientSettingsModelImplCopyWithImpl<$Res>
extends _$ClientSettingsModelCopyWithImpl<$Res, _$ClientSettingsModelImpl>
implements _$$ClientSettingsModelImplCopyWith<$Res> {
__$$ClientSettingsModelImplCopyWithImpl(_$ClientSettingsModelImpl _value,
$Res Function(_$ClientSettingsModelImpl) _then)
: super(_value, _then);
@pragma('vm:prefer-inline')
@override
$Res call({
Object? syncPath = freezed,
Object? position = null,
Object? size = null,
Object? timeOut = freezed,
Object? nextUpDateCutoff = freezed,
Object? themeMode = null,
Object? themeColor = freezed,
Object? amoledBlack = null,
Object? blurPlaceHolders = null,
Object? blurUpcomingEpisodes = null,
Object? selectedLocale = freezed,
Object? enableMediaKeys = null,
Object? posterSize = null,
Object? pinchPosterZoom = null,
Object? mouseDragSupport = null,
Object? libraryPageSize = freezed,
}) {
return _then(_$ClientSettingsModelImpl(
syncPath: freezed == syncPath
? _value.syncPath
: syncPath // ignore: cast_nullable_to_non_nullable
as String?,
position: null == position
? _value.position
: position // ignore: cast_nullable_to_non_nullable
as Vector2,
size: null == size
? _value.size
: size // ignore: cast_nullable_to_non_nullable
as Vector2,
timeOut: freezed == timeOut
? _value.timeOut
: timeOut // ignore: cast_nullable_to_non_nullable
as Duration?,
nextUpDateCutoff: freezed == nextUpDateCutoff
? _value.nextUpDateCutoff
: nextUpDateCutoff // ignore: cast_nullable_to_non_nullable
as Duration?,
themeMode: null == themeMode
? _value.themeMode
: themeMode // ignore: cast_nullable_to_non_nullable
as ThemeMode,
themeColor: freezed == themeColor
? _value.themeColor
: themeColor // ignore: cast_nullable_to_non_nullable
as ColorThemes?,
amoledBlack: null == amoledBlack
? _value.amoledBlack
: amoledBlack // ignore: cast_nullable_to_non_nullable
as bool,
blurPlaceHolders: null == blurPlaceHolders
? _value.blurPlaceHolders
: blurPlaceHolders // ignore: cast_nullable_to_non_nullable
as bool,
blurUpcomingEpisodes: null == blurUpcomingEpisodes
? _value.blurUpcomingEpisodes
: blurUpcomingEpisodes // ignore: cast_nullable_to_non_nullable
as bool,
selectedLocale: freezed == selectedLocale
? _value.selectedLocale
: selectedLocale // ignore: cast_nullable_to_non_nullable
as Locale?,
enableMediaKeys: null == enableMediaKeys
? _value.enableMediaKeys
: enableMediaKeys // ignore: cast_nullable_to_non_nullable
as bool,
posterSize: null == posterSize
? _value.posterSize
: posterSize // ignore: cast_nullable_to_non_nullable
as double,
pinchPosterZoom: null == pinchPosterZoom
? _value.pinchPosterZoom
: pinchPosterZoom // ignore: cast_nullable_to_non_nullable
as bool,
mouseDragSupport: null == mouseDragSupport
? _value.mouseDragSupport
: mouseDragSupport // ignore: cast_nullable_to_non_nullable
as bool,
libraryPageSize: freezed == libraryPageSize
? _value.libraryPageSize
: libraryPageSize // ignore: cast_nullable_to_non_nullable
as int?,
));
}
}
/// @nodoc
@JsonSerializable()
class _$ClientSettingsModelImpl
with DiagnosticableTreeMixin
implements _ClientSettingsModel {
_$ClientSettingsModelImpl(
{this.syncPath,
this.position = const Vector2(x: 0, y: 0),
this.size = const Vector2(x: 1280, y: 720),
this.timeOut = const Duration(seconds: 30),
this.nextUpDateCutoff,
this.themeMode = ThemeMode.system,
this.themeColor,
this.amoledBlack = false,
this.blurPlaceHolders = false,
this.blurUpcomingEpisodes = false,
@LocaleConvert() this.selectedLocale,
this.enableMediaKeys = true,
this.posterSize = 1.0,
this.pinchPosterZoom = false,
this.mouseDragSupport = false,
this.libraryPageSize});
factory _$ClientSettingsModelImpl.fromJson(Map<String, dynamic> json) =>
_$$ClientSettingsModelImplFromJson(json);
@override
final String? syncPath;
@override
@JsonKey()
final Vector2 position;
@override
@JsonKey()
final Vector2 size;
@override
@JsonKey()
final Duration? timeOut;
@override
final Duration? nextUpDateCutoff;
@override
@JsonKey()
final ThemeMode themeMode;
@override
final ColorThemes? themeColor;
@override
@JsonKey()
final bool amoledBlack;
@override
@JsonKey()
final bool blurPlaceHolders;
@override
@JsonKey()
final bool blurUpcomingEpisodes;
@override
@LocaleConvert()
final Locale? selectedLocale;
@override
@JsonKey()
final bool enableMediaKeys;
@override
@JsonKey()
final double posterSize;
@override
@JsonKey()
final bool pinchPosterZoom;
@override
@JsonKey()
final bool mouseDragSupport;
@override
final int? libraryPageSize;
@override
String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) {
return 'ClientSettingsModel(syncPath: $syncPath, position: $position, size: $size, timeOut: $timeOut, nextUpDateCutoff: $nextUpDateCutoff, themeMode: $themeMode, themeColor: $themeColor, amoledBlack: $amoledBlack, blurPlaceHolders: $blurPlaceHolders, blurUpcomingEpisodes: $blurUpcomingEpisodes, selectedLocale: $selectedLocale, enableMediaKeys: $enableMediaKeys, posterSize: $posterSize, pinchPosterZoom: $pinchPosterZoom, mouseDragSupport: $mouseDragSupport, libraryPageSize: $libraryPageSize)';
}
@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties
..add(DiagnosticsProperty('type', 'ClientSettingsModel'))
..add(DiagnosticsProperty('syncPath', syncPath))
..add(DiagnosticsProperty('position', position))
..add(DiagnosticsProperty('size', size))
..add(DiagnosticsProperty('timeOut', timeOut))
..add(DiagnosticsProperty('nextUpDateCutoff', nextUpDateCutoff))
..add(DiagnosticsProperty('themeMode', themeMode))
..add(DiagnosticsProperty('themeColor', themeColor))
..add(DiagnosticsProperty('amoledBlack', amoledBlack))
..add(DiagnosticsProperty('blurPlaceHolders', blurPlaceHolders))
..add(DiagnosticsProperty('blurUpcomingEpisodes', blurUpcomingEpisodes))
..add(DiagnosticsProperty('selectedLocale', selectedLocale))
..add(DiagnosticsProperty('enableMediaKeys', enableMediaKeys))
..add(DiagnosticsProperty('posterSize', posterSize))
..add(DiagnosticsProperty('pinchPosterZoom', pinchPosterZoom))
..add(DiagnosticsProperty('mouseDragSupport', mouseDragSupport))
..add(DiagnosticsProperty('libraryPageSize', libraryPageSize));
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$ClientSettingsModelImpl &&
(identical(other.syncPath, syncPath) ||
other.syncPath == syncPath) &&
(identical(other.position, position) ||
other.position == position) &&
(identical(other.size, size) || other.size == size) &&
(identical(other.timeOut, timeOut) || other.timeOut == timeOut) &&
(identical(other.nextUpDateCutoff, nextUpDateCutoff) ||
other.nextUpDateCutoff == nextUpDateCutoff) &&
(identical(other.themeMode, themeMode) ||
other.themeMode == themeMode) &&
(identical(other.themeColor, themeColor) ||
other.themeColor == themeColor) &&
(identical(other.amoledBlack, amoledBlack) ||
other.amoledBlack == amoledBlack) &&
(identical(other.blurPlaceHolders, blurPlaceHolders) ||
other.blurPlaceHolders == blurPlaceHolders) &&
(identical(other.blurUpcomingEpisodes, blurUpcomingEpisodes) ||
other.blurUpcomingEpisodes == blurUpcomingEpisodes) &&
(identical(other.selectedLocale, selectedLocale) ||
other.selectedLocale == selectedLocale) &&
(identical(other.enableMediaKeys, enableMediaKeys) ||
other.enableMediaKeys == enableMediaKeys) &&
(identical(other.posterSize, posterSize) ||
other.posterSize == posterSize) &&
(identical(other.pinchPosterZoom, pinchPosterZoom) ||
other.pinchPosterZoom == pinchPosterZoom) &&
(identical(other.mouseDragSupport, mouseDragSupport) ||
other.mouseDragSupport == mouseDragSupport) &&
(identical(other.libraryPageSize, libraryPageSize) ||
other.libraryPageSize == libraryPageSize));
}
@JsonKey(ignore: true)
@override
int get hashCode => Object.hash(
runtimeType,
syncPath,
position,
size,
timeOut,
nextUpDateCutoff,
themeMode,
themeColor,
amoledBlack,
blurPlaceHolders,
blurUpcomingEpisodes,
selectedLocale,
enableMediaKeys,
posterSize,
pinchPosterZoom,
mouseDragSupport,
libraryPageSize);
@JsonKey(ignore: true)
@override
@pragma('vm:prefer-inline')
_$$ClientSettingsModelImplCopyWith<_$ClientSettingsModelImpl> get copyWith =>
__$$ClientSettingsModelImplCopyWithImpl<_$ClientSettingsModelImpl>(
this, _$identity);
@override
Map<String, dynamic> toJson() {
return _$$ClientSettingsModelImplToJson(
this,
);
}
}
abstract class _ClientSettingsModel implements ClientSettingsModel {
factory _ClientSettingsModel(
{final String? syncPath,
final Vector2 position,
final Vector2 size,
final Duration? timeOut,
final Duration? nextUpDateCutoff,
final ThemeMode themeMode,
final ColorThemes? themeColor,
final bool amoledBlack,
final bool blurPlaceHolders,
final bool blurUpcomingEpisodes,
@LocaleConvert() final Locale? selectedLocale,
final bool enableMediaKeys,
final double posterSize,
final bool pinchPosterZoom,
final bool mouseDragSupport,
final int? libraryPageSize}) = _$ClientSettingsModelImpl;
factory _ClientSettingsModel.fromJson(Map<String, dynamic> json) =
_$ClientSettingsModelImpl.fromJson;
@override
String? get syncPath;
@override
Vector2 get position;
@override
Vector2 get size;
@override
Duration? get timeOut;
@override
Duration? get nextUpDateCutoff;
@override
ThemeMode get themeMode;
@override
ColorThemes? get themeColor;
@override
bool get amoledBlack;
@override
bool get blurPlaceHolders;
@override
bool get blurUpcomingEpisodes;
@override
@LocaleConvert()
Locale? get selectedLocale;
@override
bool get enableMediaKeys;
@override
double get posterSize;
@override
bool get pinchPosterZoom;
@override
bool get mouseDragSupport;
@override
int? get libraryPageSize;
@override
@JsonKey(ignore: true)
_$$ClientSettingsModelImplCopyWith<_$ClientSettingsModelImpl> get copyWith =>
throw _privateConstructorUsedError;
}

View file

@ -0,0 +1,83 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'client_settings_model.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
_$ClientSettingsModelImpl _$$ClientSettingsModelImplFromJson(
Map<String, dynamic> json) =>
_$ClientSettingsModelImpl(
syncPath: json['syncPath'] as String?,
position: json['position'] == null
? const Vector2(x: 0, y: 0)
: Vector2.fromJson(json['position'] as String),
size: json['size'] == null
? const Vector2(x: 1280, y: 720)
: Vector2.fromJson(json['size'] as String),
timeOut: json['timeOut'] == null
? const Duration(seconds: 30)
: Duration(microseconds: (json['timeOut'] as num).toInt()),
nextUpDateCutoff: json['nextUpDateCutoff'] == null
? null
: Duration(microseconds: (json['nextUpDateCutoff'] as num).toInt()),
themeMode: $enumDecodeNullable(_$ThemeModeEnumMap, json['themeMode']) ??
ThemeMode.system,
themeColor: $enumDecodeNullable(_$ColorThemesEnumMap, json['themeColor']),
amoledBlack: json['amoledBlack'] as bool? ?? false,
blurPlaceHolders: json['blurPlaceHolders'] as bool? ?? false,
blurUpcomingEpisodes: json['blurUpcomingEpisodes'] as bool? ?? false,
selectedLocale:
const LocaleConvert().fromJson(json['selectedLocale'] as String?),
enableMediaKeys: json['enableMediaKeys'] as bool? ?? true,
posterSize: (json['posterSize'] as num?)?.toDouble() ?? 1.0,
pinchPosterZoom: json['pinchPosterZoom'] as bool? ?? false,
mouseDragSupport: json['mouseDragSupport'] as bool? ?? false,
libraryPageSize: (json['libraryPageSize'] as num?)?.toInt(),
);
Map<String, dynamic> _$$ClientSettingsModelImplToJson(
_$ClientSettingsModelImpl instance) =>
<String, dynamic>{
'syncPath': instance.syncPath,
'position': instance.position,
'size': instance.size,
'timeOut': instance.timeOut?.inMicroseconds,
'nextUpDateCutoff': instance.nextUpDateCutoff?.inMicroseconds,
'themeMode': _$ThemeModeEnumMap[instance.themeMode]!,
'themeColor': _$ColorThemesEnumMap[instance.themeColor],
'amoledBlack': instance.amoledBlack,
'blurPlaceHolders': instance.blurPlaceHolders,
'blurUpcomingEpisodes': instance.blurUpcomingEpisodes,
'selectedLocale': const LocaleConvert().toJson(instance.selectedLocale),
'enableMediaKeys': instance.enableMediaKeys,
'posterSize': instance.posterSize,
'pinchPosterZoom': instance.pinchPosterZoom,
'mouseDragSupport': instance.mouseDragSupport,
'libraryPageSize': instance.libraryPageSize,
};
const _$ThemeModeEnumMap = {
ThemeMode.system: 'system',
ThemeMode.light: 'light',
ThemeMode.dark: 'dark',
};
const _$ColorThemesEnumMap = {
ColorThemes.fladder: 'fladder',
ColorThemes.deepOrange: 'deepOrange',
ColorThemes.amber: 'amber',
ColorThemes.green: 'green',
ColorThemes.lightGreen: 'lightGreen',
ColorThemes.lime: 'lime',
ColorThemes.cyan: 'cyan',
ColorThemes.blue: 'blue',
ColorThemes.lightBlue: 'lightBlue',
ColorThemes.indigo: 'indigo',
ColorThemes.deepBlue: 'deepBlue',
ColorThemes.brown: 'brown',
ColorThemes.purple: 'purple',
ColorThemes.deepPurple: 'deepPurple',
ColorThemes.blueGrey: 'blueGrey',
};

View file

@ -0,0 +1,108 @@
import 'dart:convert';
import 'package:collection/collection.dart';
import 'package:fladder/util/localization_helper.dart';
import 'package:flutter/material.dart';
enum HomeCarouselSettings {
off,
nextUp,
cont,
combined,
;
const HomeCarouselSettings();
String label(BuildContext context) => switch (this) {
HomeCarouselSettings.off => context.localized.hide,
HomeCarouselSettings.nextUp => context.localized.nextUp,
HomeCarouselSettings.cont => context.localized.settingsContinue,
HomeCarouselSettings.combined => context.localized.combined,
};
String toMap() {
return toString();
}
static HomeCarouselSettings fromMap(String value) {
return HomeCarouselSettings.values.firstWhereOrNull((element) => element.name == value) ??
HomeCarouselSettings.combined;
}
}
enum HomeNextUp {
off,
nextUp,
cont,
combined,
separate,
;
const HomeNextUp();
String label(BuildContext context) => switch (this) {
HomeNextUp.off => context.localized.hide,
HomeNextUp.nextUp => context.localized.nextUp,
HomeNextUp.cont => context.localized.settingsContinue,
HomeNextUp.combined => context.localized.combined,
HomeNextUp.separate => context.localized.separate,
};
String toMap() {
return toString();
}
static HomeNextUp fromMap(String value) {
return HomeNextUp.values.firstWhereOrNull((element) => element.name == value) ?? HomeNextUp.separate;
}
}
class HomeSettingsModel {
final HomeCarouselSettings carouselSettings;
final HomeNextUp nextUp;
HomeSettingsModel({
this.carouselSettings = HomeCarouselSettings.combined,
this.nextUp = HomeNextUp.separate,
});
HomeSettingsModel copyWith({
HomeCarouselSettings? carouselSettings,
HomeNextUp? nextUp,
}) {
return HomeSettingsModel(
carouselSettings: carouselSettings ?? this.carouselSettings,
nextUp: nextUp ?? this.nextUp,
);
}
Map<String, dynamic> toMap() {
return {
'carouselSettings': carouselSettings.toMap(),
'nextUp': nextUp.toMap(),
};
}
factory HomeSettingsModel.fromMap(Map<String, dynamic> map) {
return HomeSettingsModel(
carouselSettings: HomeCarouselSettings.fromMap(map['carouselSettings']),
nextUp: HomeNextUp.fromMap(map['nextUp']),
);
}
String toJson() => json.encode(toMap());
factory HomeSettingsModel.fromJson(String source) => HomeSettingsModel.fromMap(json.decode(source));
@override
String toString() => 'HomeSettingsModel(carouselSettings: $carouselSettings, nextUp: $nextUp)';
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
return other is HomeSettingsModel && other.carouselSettings == carouselSettings && other.nextUp == nextUp;
}
@override
int get hashCode => carouselSettings.hashCode ^ nextUp.hashCode;
}

View file

@ -0,0 +1,254 @@
// ignore_for_file: public_member_api_docs, sort_constructors_first
import 'dart:convert';
import 'dart:math' as math;
import 'package:collection/collection.dart';
import 'package:fladder/providers/settings/subtitle_settings_provider.dart';
import 'package:fladder/providers/settings/video_player_settings_provider.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:google_fonts/google_fonts.dart';
class SubtitleSettingsModel {
final double fontSize;
final FontWeight fontWeight;
final double verticalOffset;
final Color color;
final Color outlineColor;
final double outlineSize;
final Color backGroundColor;
final double shadow;
const SubtitleSettingsModel({
this.fontSize = 60,
this.fontWeight = FontWeight.normal,
this.verticalOffset = 0.10,
this.color = Colors.white,
this.outlineColor = const Color.fromRGBO(0, 0, 0, 0.85),
this.outlineSize = 4,
this.backGroundColor = const Color.fromARGB(0, 0, 0, 0),
this.shadow = 0.5,
});
SubtitleSettingsModel copyWith({
double? fontSize,
FontWeight? fontWeight,
double? verticalOffset,
Color? color,
Color? outlineColor,
double? outlineSize,
Color? backGroundColor,
double? shadow,
}) {
return SubtitleSettingsModel(
fontSize: fontSize ?? this.fontSize,
fontWeight: fontWeight ?? this.fontWeight,
verticalOffset: verticalOffset ?? this.verticalOffset,
color: color ?? this.color,
outlineColor: outlineColor ?? this.outlineColor,
outlineSize: outlineSize ?? this.outlineSize,
backGroundColor: backGroundColor ?? this.backGroundColor,
shadow: shadow ?? this.shadow,
);
}
TextStyle get backGroundStyle {
return style.copyWith(
shadows: (shadow > 0.01)
? [
Shadow(
blurRadius: 16,
color: Colors.black.withOpacity(shadow),
),
Shadow(
blurRadius: 8,
color: Colors.black.withOpacity(shadow),
),
]
: null,
foreground: Paint()
..style = PaintingStyle.stroke
..strokeWidth = outlineSize * (fontSize / 30)
..color = outlineColor
..strokeCap = StrokeCap.round
..strokeJoin = StrokeJoin.round,
);
}
TextStyle get style {
return TextStyle(
height: 1.4,
fontSize: fontSize,
fontWeight: fontWeight,
fontFamily: GoogleFonts.openSans().fontFamily,
letterSpacing: 0.0,
wordSpacing: 0.0,
color: color,
);
}
Map<String, dynamic> toMap() {
return <String, dynamic>{
'fontSize': fontSize,
'fontWeight': fontWeight.value,
'verticalOffset': verticalOffset,
'color': color.value,
'outlineColor': outlineColor.value,
'outlineSize': outlineSize,
'backGroundColor': backGroundColor.value,
'shadow': shadow,
};
}
String toJson() => json.encode(toMap());
factory SubtitleSettingsModel.fromJson(String source) => SubtitleSettingsModel.fromMap(json.decode(source));
factory SubtitleSettingsModel.fromMap(Map<String, dynamic> map) {
return const SubtitleSettingsModel().copyWith(
fontSize: map['fontSize'] as double?,
fontWeight: FontWeight.values.firstWhereOrNull((element) => element.index == map['fontWeight'] as int?),
verticalOffset: map['verticalOffset'] as double?,
color: map['color'] != null ? Color(map['color'] as int) : null,
outlineColor: map['outlineColor'] != null ? Color(map['outlineColor'] as int) : null,
outlineSize: map['outlineSize'] as double?,
backGroundColor: map['backGroundColor'] != null ? Color(map['backGroundColor'] as int) : null,
shadow: map['shadow'] as double?,
);
}
@override
String toString() {
return 'SubtitleSettingsModel(fontSize: $fontSize, fontWeight: $fontWeight, verticalOffset: $verticalOffset, color: $color, outlineColor: $outlineColor, outlineSize: $outlineSize, backGroundColor: $backGroundColor, shadow: $shadow)';
}
@override
bool operator ==(covariant SubtitleSettingsModel other) {
if (identical(this, other)) return true;
return other.fontSize == fontSize &&
other.fontWeight == fontWeight &&
other.verticalOffset == verticalOffset &&
other.color == color &&
other.outlineColor == outlineColor &&
other.outlineSize == outlineSize &&
other.backGroundColor == backGroundColor &&
other.shadow == shadow;
}
@override
int get hashCode {
return fontSize.hashCode ^
fontWeight.hashCode ^
verticalOffset.hashCode ^
color.hashCode ^
outlineColor.hashCode ^
outlineSize.hashCode ^
backGroundColor.hashCode ^
shadow.hashCode;
}
}
class SubtitleText extends ConsumerWidget {
final SubtitleSettingsModel subModel;
final EdgeInsets padding;
final String text;
final double offset;
const SubtitleText({
required this.subModel,
required this.padding,
required this.offset,
required this.text,
super.key,
});
// The reference width for calculating the visible text scale factor.
static const kTextScaleFactorReferenceWidth = 1920.0;
// The reference height for calculating the visible text scale factor.
static const kTextScaleFactorReferenceHeight = 1080.0;
@override
Widget build(BuildContext context, WidgetRef ref) {
final fillScreen = ref.watch(videoPlayerSettingsProvider.select((value) => value.fillScreen));
return Padding(
padding: (fillScreen ? EdgeInsets.zero : EdgeInsets.only(left: padding.left, right: padding.right))
.add(const EdgeInsets.all(16)),
child: LayoutBuilder(
builder: (context, constraints) {
final textScale = MediaQuery.textScalerOf(context)
.scale((ref.read(subtitleSettingsProvider.select((value) => value.fontSize)) *
math.sqrt(
((constraints.maxWidth * constraints.maxHeight) /
(kTextScaleFactorReferenceWidth * kTextScaleFactorReferenceHeight))
.clamp(0.0, 1.0),
)));
// Function to calculate the height of the text
double getTextHeight(BuildContext context, String text, TextStyle style) {
final TextPainter textPainter = TextPainter(
text: TextSpan(text: text, style: style),
textDirection: TextDirection.ltr,
textScaler: MediaQuery.textScalerOf(context),
)..layout(minWidth: 0, maxWidth: double.infinity);
return textPainter.height;
}
// Calculate the available height for the text alignment
double availableHeight = constraints.maxHeight;
// Calculate the desired position based on the percentage
double desiredPosition = availableHeight * offset;
// Get the height of the Text widget with the current font style
double textHeight = getTextHeight(context, text, subModel.style);
// Calculate the position to keep the text within visible bounds
double position = desiredPosition - textHeight / 2;
// Ensure the text doesn't go off-screen
position = position.clamp(0, availableHeight - textHeight);
return IgnorePointer(
child: Stack(
alignment: Alignment.bottomCenter,
children: [
Positioned(
bottom: position,
child: Container(
constraints: BoxConstraints(maxWidth: constraints.maxWidth, maxHeight: constraints.maxHeight),
decoration: BoxDecoration(
color: subModel.backGroundColor,
borderRadius: BorderRadius.circular(16),
),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Text(
text,
style: subModel.backGroundStyle.copyWith(fontSize: textScale),
textAlign: TextAlign.center,
),
),
),
),
Positioned(
bottom: position,
child: Container(
constraints: BoxConstraints(maxWidth: constraints.maxWidth, maxHeight: constraints.maxHeight),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Text(
text,
style: subModel.style.copyWith(fontSize: textScale),
textAlign: TextAlign.center,
),
),
),
)
],
),
);
},
),
);
}
}

View file

@ -0,0 +1,113 @@
// ignore_for_file: public_member_api_docs, sort_constructors_first
import 'dart:convert';
import 'package:collection/collection.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
class VideoPlayerSettingsModel {
final double? screenBrightness;
final BoxFit videoFit;
final bool fillScreen;
final bool hardwareAccel;
final bool useLibass;
final double internalVolume;
final String? audioDevice;
const VideoPlayerSettingsModel({
this.screenBrightness,
this.videoFit = BoxFit.contain,
this.fillScreen = false,
this.hardwareAccel = true,
this.useLibass = false,
this.internalVolume = 100,
this.audioDevice,
});
double get volume => switch (defaultTargetPlatform) {
TargetPlatform.android || TargetPlatform.iOS => 100,
_ => internalVolume,
};
VideoPlayerSettingsModel copyWith({
ValueGetter<double?>? screenBrightness,
BoxFit? videoFit,
bool? fillScreen,
bool? hardwareAccel,
bool? useLibass,
double? internalVolume,
ValueGetter<String?>? audioDevice,
}) {
return VideoPlayerSettingsModel(
screenBrightness: screenBrightness != null ? screenBrightness() : this.screenBrightness,
videoFit: videoFit ?? this.videoFit,
fillScreen: fillScreen ?? this.fillScreen,
hardwareAccel: hardwareAccel ?? this.hardwareAccel,
useLibass: useLibass ?? this.useLibass,
internalVolume: internalVolume ?? this.internalVolume,
audioDevice: audioDevice != null ? audioDevice() : this.audioDevice,
);
}
Map<String, dynamic> toMap() {
return {
'screenBrightness': screenBrightness,
'videoFit': videoFit.name,
'fillScreen': fillScreen,
'hardwareAccel': hardwareAccel,
'useLibass': useLibass,
'internalVolume': internalVolume,
'audioDevice': audioDevice,
};
}
factory VideoPlayerSettingsModel.fromMap(Map<String, dynamic> map) {
return VideoPlayerSettingsModel(
screenBrightness: map['screenBrightness']?.toDouble(),
videoFit: BoxFit.values.firstWhereOrNull((element) => element.name == map['videoFit']) ?? BoxFit.contain,
fillScreen: map['fillScreen'] ?? false,
hardwareAccel: map['hardwareAccel'] ?? false,
useLibass: map['useLibass'] ?? false,
internalVolume: map['internalVolume']?.toDouble() ?? 0.0,
audioDevice: map['audioDevice'],
);
}
String toJson() => json.encode(toMap());
factory VideoPlayerSettingsModel.fromJson(String source) => VideoPlayerSettingsModel.fromMap(json.decode(source));
@override
String toString() {
return 'VideoPlayerSettingsModel(screenBrightness: $screenBrightness, videoFit: $videoFit, fillScreen: $fillScreen, hardwareAccel: $hardwareAccel, useLibass: $useLibass, internalVolume: $internalVolume, audioDevice: $audioDevice)';
}
bool playerSame(VideoPlayerSettingsModel other) {
return other.hardwareAccel == hardwareAccel && other.useLibass == useLibass;
}
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
return other is VideoPlayerSettingsModel &&
other.screenBrightness == screenBrightness &&
other.videoFit == videoFit &&
other.fillScreen == fillScreen &&
other.hardwareAccel == hardwareAccel &&
other.useLibass == useLibass &&
other.internalVolume == internalVolume &&
other.audioDevice == audioDevice;
}
@override
int get hashCode {
return screenBrightness.hashCode ^
videoFit.hashCode ^
fillScreen.hashCode ^
hardwareAccel.hashCode ^
useLibass.hashCode ^
internalVolume.hashCode ^
audioDevice.hashCode;
}
}