Skip to content

Commit

Permalink
Merge branch 'redesign' into enable-fmp4-transcoding-container
Browse files Browse the repository at this point in the history
  • Loading branch information
Chaphasilor committed Nov 3, 2024
2 parents 49a26ae + 9996889 commit 69555d4
Show file tree
Hide file tree
Showing 27 changed files with 738 additions and 290 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,8 @@ jobs:
# with:
# distribution: 'zulu'
# java-version: '17'
- name: Set up Rust (for smtc_windows)
uses: hecrj/setup-rust-action@v2
- name: Set up Flutter
uses: subosito/flutter-action@v2
with:
Expand Down
15 changes: 8 additions & 7 deletions lib/components/LanguageSelectionScreen/language_list.dart
Original file line number Diff line number Diff line change
Expand Up @@ -67,19 +67,20 @@ class LanguageListTile extends StatelessWidget {
this.locale,
});

final Locale? locale;
final Locale? locale; // null if system language

@override
Widget build(BuildContext context) {
return RadioListTile<Locale?>(
title: Text(locale?.nativeDisplayLanguage ??
AppLocalizations.of(context)!.system),
subtitle: locale == null
? null
: Text((LocaleHelper.locale == null
? locale!.defaultDisplayLanguage
: locale!.displayLanguageIn(LocaleHelper.locale!)) ??
"???"),
subtitle: locale != null
? Text(
LocaleHelper.locale != null
? locale!.displayLanguageIn(LocaleHelper.locale!)
: locale!.defaultDisplayLanguage,
)
: null,
value: locale,
groupValue: LocaleHelper.locale,
onChanged: (_) {
Expand Down
30 changes: 17 additions & 13 deletions lib/components/LoginScreen/login_flow.dart
Original file line number Diff line number Diff line change
Expand Up @@ -270,21 +270,25 @@ class ConnectionState {
class JellyfinServerClientDiscovery {
static final _clientDiscoveryLogger = Logger("JellyfinServerClientDiscovery");

late RawDatagramSocket socket;
bool isDisposed = false;
RawDatagramSocket? _socket;
bool _isDisposed = false;

void discoverServers(
void Function(ClientDiscoveryResponse response) onServerFound) async {
isDisposed = false;
_isDisposed = false;

socket = await RawDatagramSocket.bind(InternetAddress.anyIPv4, 0);
socket.broadcastEnabled =
_socket = await RawDatagramSocket.bind(InternetAddress.anyIPv4, 0);

// We have to use ? throughout since _socket isn't final, although at this
// point in the code it should never be null

_socket?.broadcastEnabled =
true; // important to allow sending to broadcast address
socket.multicastHops = 5; // to account for weird network setups
_socket?.multicastHops = 5; // to account for weird network setups

socket.listen((event) {
_socket?.listen((event) {
if (event == RawSocketEvent.read) {
final datagram = socket.receive();
final datagram = _socket?.receive();
if (datagram != null) {
_clientDiscoveryLogger
.finest("Received datagram: ${utf8.decode(datagram.data)}");
Expand All @@ -305,16 +309,16 @@ class JellyfinServerClientDiscovery {

_clientDiscoveryLogger.fine("Sending discovery messages");

socket.send(message.codeUnits, broadcastAddress, destinationPort);
_socket?.send(message.codeUnits, broadcastAddress, destinationPort);

while (!isDisposed) {
while (!_isDisposed) {
await Future.delayed(const Duration(milliseconds: 1500));
socket.send(message.codeUnits, broadcastAddress, destinationPort);
_socket?.send(message.codeUnits, broadcastAddress, destinationPort);
}
}

void dispose() {
isDisposed = true;
socket.close();
_isDisposed = true;
_socket?.close();
}
}
15 changes: 3 additions & 12 deletions lib/components/PlaybackHistoryScreen/playback_history_list.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,15 @@ import 'package:finamp/services/audio_service_helper.dart';
import 'package:finamp/services/locale_helper.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:intl/date_symbol_data_local.dart';
import 'package:get_it/get_it.dart';
import 'package:intl/intl.dart';

import '../../services/playback_history_service.dart';
import '../../models/jellyfin_models.dart' as jellyfin_models;
import '../../services/playback_history_service.dart';
import 'playback_history_list_tile.dart';

class PlaybackHistoryList extends StatelessWidget {
const PlaybackHistoryList({Key? key}) : super(key: key);
const PlaybackHistoryList({super.key});

@override
Widget build(BuildContext context) {
Expand All @@ -28,13 +27,9 @@ class PlaybackHistoryList extends StatelessWidget {
builder: (context, snapshot) {
if (snapshot.hasData) {
history = snapshot.data;
// groupedHistory = playbackHistoryService.getHistoryGroupedByDate();
// groupedHistory = playbackHistoryService.getHistoryGroupedByHour();
groupedHistory =
playbackHistoryService.getHistoryGroupedDynamically();

print(groupedHistory);

return CustomScrollView(
// use nested SliverList.builder()s to show history items grouped by date
slivers: groupedHistory.map((group) {
Expand Down Expand Up @@ -73,11 +68,7 @@ class PlaybackHistoryList extends StatelessWidget {
);

final now = DateTime.now();
final String localeString = (LocaleHelper.locale != null)
? ((LocaleHelper.locale?.countryCode != null)
? "${LocaleHelper.locale?.languageCode.toLowerCase()}_${LocaleHelper.locale?.countryCode?.toUpperCase()}"
: LocaleHelper.locale.toString())
: "en_US";
final String? localeString = LocaleHelper.localeString;

return index == 0
? Column(
Expand Down
4 changes: 3 additions & 1 deletion lib/components/PlayerScreen/artist_chip.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

187 changes: 107 additions & 80 deletions lib/components/PlayerScreen/feature_chips.dart
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ class FeatureState {
final FinampSettings settings;
final MetadataProvider? metadata;

FinampFeatureChipsConfiguration get configuration =>
settings.featureChipsConfiguration;

bool get isDownloaded => metadata?.isDownloaded ?? false;
bool get isTranscoding =>
!isDownloaded && (currentTrack?.item.extras?["shouldTranscode"] ?? false);
Expand Down Expand Up @@ -63,112 +66,136 @@ class FeatureState {
),
);
}

for (var feature in configuration.features) {

// TODO this will likely be extremely outdated if offline, hide?
if (currentTrack?.baseItem?.userData?.playCount != null) {
features.add(
FeatureProperties(
text: AppLocalizations.of(context)!
.playCountValue(currentTrack!.baseItem!.userData?.playCount ?? 0),
),
);
}

if (currentTrack?.baseItem?.people?.isNotEmpty ?? false) {
currentTrack?.baseItem?.people?.forEach((person) {
features.add(
FeatureProperties(
text: "${person.role}: ${person.name}",
),
);
});
}

if (currentTrack?.item.extras?["downloadedSongPath"] != null) {
features.add(
FeatureProperties(
text: AppLocalizations.of(context)!.playbackModeLocal,
),
);
} else {
if (isTranscoding) {
// TODO this will likely be extremely outdated if offline, hide?
if (feature == FinampFeatureChipType.playCount &&
currentTrack?.baseItem?.userData?.playCount != null) {
features.add(
FeatureProperties(
text: AppLocalizations.of(context)!.playbackModeTranscoding,
),
);
} else {
features.add(
//TODO differentiate between direct streaming and direct playing
// const FeatureProperties(
// text: "Direct Streaming",
// ),
FeatureProperties(
text: AppLocalizations.of(context)!.playbackModeDirectPlaying,
type: feature,
text: AppLocalizations.of(context)!.playCountValue(
currentTrack!.baseItem!.userData?.playCount ?? 0),
),
);
}
}

if (metadata?.mediaSourceInfo != null) {
if (bitrate != null) {
features.add(
FeatureProperties(
text:
"${container.toUpperCase()} @ ${AppLocalizations.of(context)!.kiloBitsPerSecondLabel(bitrate! ~/ 1000)}",
),
);
if (feature == FinampFeatureChipType.additionalPeople &&
(currentTrack?.baseItem?.people?.isNotEmpty ?? false)) {
currentTrack?.baseItem?.people?.forEach((person) {
features.add(
FeatureProperties(
type: feature,
text: "${person.role}: ${person.name}",
),
);
});
}

if (bitDepth != null) {
features.add(
FeatureProperties(
text: AppLocalizations.of(context)!.numberAsBit(bitDepth!),
),
);
if (feature == FinampFeatureChipType.playbackMode) {
if (currentTrack?.item.extras?["downloadedSongPath"] != null) {
features.add(
FeatureProperties(
type: feature,
text: AppLocalizations.of(context)!.playbackModeLocal,
),
);
} else {
if (isTranscoding) {
features.add(
FeatureProperties(
type: feature,
text: AppLocalizations.of(context)!.playbackModeTranscoding,
),
);
} else {
features.add(
//TODO differentiate between direct streaming and direct playing
// const FeatureProperties(
// text: "Direct Streaming",
// ),
FeatureProperties(
type: feature,
text: AppLocalizations.of(context)!.playbackModeDirectPlaying,
),
);
}
}
}

if (sampleRate != null) {
features.add(
FeatureProperties(
text: AppLocalizations.of(context)!
.numberAsKiloHertz(sampleRate! / 1000.0),
),
);
if (metadata?.mediaSourceInfo != null) {
if (feature == FinampFeatureChipType.codec ||
feature == FinampFeatureChipType.bitRate) {
// only add this feature the first time
if (!features.any((f) => f.type == FinampFeatureChipType.codec)) {
features.add(
FeatureProperties(
type: feature,
text:
"${configuration.features.contains(FinampFeatureChipType.codec) ? container.toUpperCase() : ""}${configuration.features.contains(FinampFeatureChipType.codec) && configuration.features.contains(FinampFeatureChipType.bitRate) ? " @ " : ""}${configuration.features.contains(FinampFeatureChipType.bitRate) && bitrate != null ? AppLocalizations.of(context)!.kiloBitsPerSecondLabel(bitrate! ~/ 1000) : ""}",
),
);
}
}

if (feature == FinampFeatureChipType.bitDepth && bitDepth != null) {
features.add(
FeatureProperties(
type: feature,
text: AppLocalizations.of(context)!.numberAsBit(bitDepth!),
),
);
}

if (feature == FinampFeatureChipType.sampleRate && sampleRate != null) {
features.add(
FeatureProperties(
type: feature,
text: AppLocalizations.of(context)!
.numberAsKiloHertz(sampleRate! / 1000.0),
),
);
}

if (feature == FinampFeatureChipType.size && size != null) {
features.add(
FeatureProperties(
type: feature,
text: FileSize.getSize(size),
),
);
}
}

if (size != null) {
features.add(
FeatureProperties(
text: FileSize.getSize(size),
),
);
if (feature == FinampFeatureChipType.normalizationGain &&
FinampSettingsHelper.finampSettings.volumeNormalizationActive) {
double? effectiveGainChange =
getEffectiveGainChange(currentTrack!.item, currentTrack!.baseItem);
if (effectiveGainChange != null) {
features.add(
FeatureProperties(
type: feature,
text: AppLocalizations.of(context)!.numberAsDecibel(
double.parse(effectiveGainChange.toStringAsFixed(1))),
),
);
}
}
}

if (FinampSettingsHelper.finampSettings.volumeNormalizationActive) {
double? effectiveGainChange =
getEffectiveGainChange(currentTrack!.item, currentTrack!.baseItem);
if (effectiveGainChange != null) {
features.add(
FeatureProperties(
text: AppLocalizations.of(context)!.numberAsDecibel(
double.parse(effectiveGainChange.toStringAsFixed(1))),
),
);
}
}

return features;
}
}

class FeatureProperties {
const FeatureProperties({
required this.text,
this.type,
});

final String text;
final FinampFeatureChipType? type;
}

class FeatureChips extends ConsumerWidget {
Expand Down
Loading

0 comments on commit 69555d4

Please sign in to comment.