Skip to content

Commit

Permalink
add proof-of-concept sharing panel
Browse files Browse the repository at this point in the history
- shows current sharing status and allows to toggle it
  • Loading branch information
Chaphasilor committed Sep 19, 2024
1 parent b265d9f commit 5f9317e
Show file tree
Hide file tree
Showing 5 changed files with 158 additions and 20 deletions.
11 changes: 11 additions & 0 deletions lib/components/MusicScreen/music_screen_drawer.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'package:finamp/components/server_sharing_panel.dart';
import 'package:finamp/screens/playback_history_screen.dart';
import 'package:finamp/screens/queue_restore_screen.dart';
import 'package:flutter/material.dart';
Expand Down Expand Up @@ -96,6 +97,16 @@ class MusicScreenDrawer extends StatelessWidget {
mainAxisSize: MainAxisSize.min,
children: [
const Divider(),
ListTile(
leading: const Padding(
padding: EdgeInsets.only(right: 16),
child: Icon(TablerIcons.share),
),
title: Text("Share Server"),
onTap: () => showServerSharingPanel(
context: context,
),
),
ListTile(
leading: const Padding(
padding: EdgeInsets.only(right: 16),
Expand Down
104 changes: 104 additions & 0 deletions lib/components/server_sharing_panel.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import 'package:collection/collection.dart';
import 'package:finamp/components/AddToPlaylistScreen/playlist_actions_menu.dart';
import 'package:finamp/components/themed_bottom_sheet.dart';
import 'package:finamp/models/finamp_models.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_sticky_header/flutter_sticky_header.dart';
import 'package:flutter_tabler_icons/flutter_tabler_icons.dart';
import 'package:flutter_vibrate/flutter_vibrate.dart';
import 'package:get_it/get_it.dart';
import 'package:hive/hive.dart';

import '../../models/jellyfin_models.dart';
import '../../services/favorite_provider.dart';
import '../../services/feedback_helper.dart';
import '../../services/finamp_settings_helper.dart';
import '../../services/jellyfin_api_helper.dart';
import '../../services/theme_provider.dart';

const serverSharingPanelRouteName = "/server-sharing-panel";

Future<void> showServerSharingPanel({
required BuildContext context,
FinampTheme? themeProvider,
}) async {
final isOffline = FinampSettingsHelper.finampSettings.isOffline;
final jellyfinApiHelper = GetIt.instance<JellyfinApiHelper>();

FeedbackHelper.feedback(FeedbackType.selection);

await showThemedBottomSheet(
context: context,
usePlayerTheme: true,
routeName: serverSharingPanelRouteName,
minDraggableHeight: 0.2,
buildSlivers: (context) {

final menuEntries = [
Consumer(
builder: (context, ref, child) {
FinampSettings? finampSettings =
ref.watch(finampSettingsProvider).value;
return Text("Server Sharing ${finampSettings?.serverSharingEnabled ?? false ? "Enabled" : "Disabled"}",
style: TextStyle(
color: Theme.of(context).textTheme.bodyLarge!.color!,
fontSize: 18,
fontWeight: FontWeight.w400));
},
),
const Divider(),
Consumer(
builder: (context, ref, child) {
final finampSettings =
ref.watch(finampSettingsProvider).value;
// button for toggling server sharing
return ToggleableListTile(
title: "Enable Server Sharing",
leading: const Icon(TablerIcons.share, size: 36.0),
positiveIcon: TablerIcons.check,
negativeIcon: TablerIcons.x,
initialState: (finampSettings?.serverSharingEnabled ?? false),
enabled: !isOffline,
onToggle: (bool currentState) async {
FinampSettings finampSettingsTemp = FinampSettingsHelper.finampSettings;
if (currentState) {
finampSettingsTemp.serverSharingEnabled = !currentState;
} else {
finampSettingsTemp.serverSharingEnabled = !currentState;
}
await Hive.box<FinampSettings>("FinampSettings").put("FinampSettings", finampSettingsTemp);
return finampSettingsTemp.serverSharingEnabled;
},
);
},
),
];

var menu = [
SliverStickyHeader(
header: Padding(
padding: const EdgeInsets.only(top: 6.0, bottom: 16.0),
child: Center(
child: Text(AppLocalizations.of(context)!.addRemoveFromPlaylist,
style: TextStyle(
color: Theme.of(context).textTheme.bodyLarge!.color!,
fontSize: 18,
fontWeight: FontWeight.w400)),
),
),
sliver: MenuMask(
height: 36.0,
child: SliverList(
delegate: SliverChildListDelegate.fixed(
menuEntries,
))),
),
const SliverPadding(padding: EdgeInsets.only(bottom: 100.0))
];
var stackHeight = MediaQuery.sizeOf(context).height * 0.5;
return (stackHeight, menu);
},
themeProvider: themeProvider);
}
34 changes: 19 additions & 15 deletions lib/components/themed_bottom_sheet.dart
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ typedef ScrollBuilder = Widget Function(double, List<Widget>);

Future<void> showThemedBottomSheet({
required BuildContext context,
required BaseItemDto item,
BaseItemDto? item,
required String routeName,
SliverBuilder? buildSlivers,
WrapperBuilder? buildWrapper,
Expand All @@ -31,7 +31,7 @@ Future<void> showThemedBottomSheet({
double minDraggableHeight = 0.6,
bool showDragHandle = true,
}) async {
if (usePlayerTheme) {
if (usePlayerTheme || item == null) {
// Theme will be calculated later
} else if (themeProvider == null) {
if (item.blurHash != null) {
Expand Down Expand Up @@ -73,7 +73,7 @@ Future<void> showThemedBottomSheet({
.withOpacity(0.9),
builder: (BuildContext context) {
return ThemedBottomSheet(
key: ValueKey(item.id + routeName),
key: ValueKey((item?.id ?? "") + routeName),
item: item,
usePlayerTheme: usePlayerTheme,
themeProvider: themeProvider,
Expand All @@ -88,7 +88,7 @@ Future<void> showThemedBottomSheet({
class ThemedBottomSheet extends ConsumerStatefulWidget {
const ThemedBottomSheet({
super.key,
required this.item,
this.item,
required this.usePlayerTheme,
required this.themeProvider,
this.buildSlivers,
Expand All @@ -97,7 +97,7 @@ class ThemedBottomSheet extends ConsumerStatefulWidget {
required this.showDragHandle,
});

final BaseItemDto item;
final BaseItemDto? item;
final bool usePlayerTheme;
final FinampTheme? themeProvider;
final SliverBuilder? buildSlivers;
Expand Down Expand Up @@ -134,18 +134,22 @@ class _ThemedBottomSheetState extends ConsumerState<ThemedBottomSheet> {
assert(widget.buildSlivers != null || widget.buildWrapper != null);
var brightness = ref.watch(brightnessProvider);
if (_themeProvider == null) {
var image = ref.read(albumImageProvider(AlbumImageRequest(
item: widget.item,
maxWidth: 100,
maxHeight: 100,
)));
if (image != null) {
_themeProvider = FinampTheme.fromImage(
image, widget.item.blurHash, brightness,
useIsolate: false);
} else {
if (widget.item == null) {
_themeProvider = FinampTheme.defaultTheme();
} else {
var image = ref.read(albumImageProvider(AlbumImageRequest(
item: widget.item!,
maxWidth: 100,
maxHeight: 100,
)));
if (image != null) {
_themeProvider = FinampTheme.fromImage(
image, widget.item!.blurHash, brightness,
useIsolate: false);
}
}
// If we still don't have a theme, use the default
_themeProvider ??= FinampTheme.defaultTheme();
}
return ProviderScope(
overrides: [
Expand Down
9 changes: 7 additions & 2 deletions lib/models/finamp_models.dart
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ const _showStopButtonOnMediaNotificationDefault = false;
const _showSeekControlsOnMediaNotificationDefault = true;
const _keepScreenOnOption = KeepScreenOnOption.whileLyrics;
const _keepScreenOnWhilePluggedIn = true;
const _serverSharingEnabledDefault = false;

@HiveType(typeId: 28)
class FinampSettings {
Expand Down Expand Up @@ -193,7 +194,8 @@ class FinampSettings {
this.showStopButtonOnMediaNotification = _showStopButtonOnMediaNotificationDefault,
this.showSeekControlsOnMediaNotification = _showSeekControlsOnMediaNotificationDefault,
this.keepScreenOnOption = _keepScreenOnOption,
this.keepScreenOnWhilePluggedIn = _keepScreenOnWhilePluggedIn
this.keepScreenOnWhilePluggedIn = _keepScreenOnWhilePluggedIn,
this.serverSharingEnabled = _serverSharingEnabledDefault,
});

@HiveField(0, defaultValue: _isOfflineDefault)
Expand Down Expand Up @@ -431,6 +433,9 @@ class FinampSettings {
@HiveField(73, defaultValue: _keepScreenOnWhilePluggedIn)
bool keepScreenOnWhilePluggedIn;

@HiveField(74, defaultValue: _serverSharingEnabledDefault)
bool serverSharingEnabled;

static Future<FinampSettings> create() async {
final downloadLocation = await DownloadLocation.create(
name: "Internal Storage",
Expand Down Expand Up @@ -2235,4 +2240,4 @@ enum KeepScreenOnOption {
return AppLocalizations.of(context)!.keepScreenOnWhileLyrics;
}
}
}
}
20 changes: 17 additions & 3 deletions lib/services/server_discovery_emulation_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import 'dart:convert';
import 'dart:io';

import 'package:finamp/models/jellyfin_models.dart';
import 'package:finamp/services/finamp_settings_helper.dart';
import 'package:finamp/services/finamp_user_helper.dart';
import 'package:get_it/get_it.dart';
import 'package:logging/logging.dart';
Expand All @@ -15,14 +16,26 @@ class JellyfinServerDiscoveryEmulationService {
final _finampUserHelper = GetIt.instance<FinampUserHelper>();

late RawDatagramSocket socket;
bool isDisposed = false;
bool isSharing = false;

JellyfinServerDiscoveryEmulationService() {
advertiseServer();
// listen for Finamp settings change and enable/disable server discovery emulation
FinampSettingsHelper.finampSettingsListener.addListener(() {
if (isSharing != FinampSettingsHelper.finampSettings.serverSharingEnabled) {
if (FinampSettingsHelper.finampSettings.serverSharingEnabled) {
advertiseServer();
} else {
dispose();
}
}
});

}

void advertiseServer() async {

isSharing = true;

const discoveryMessage =
"who is JellyfinServer?"; // doesn't seem to be case sensitive, but the Kotlin SDK uses this capitalization
final broadcastAddress =
Expand Down Expand Up @@ -63,7 +76,8 @@ class JellyfinServerDiscoveryEmulationService {
}

void dispose() {
isDisposed = true;
isSharing = false;
socket.close();
_serverDiscoveryEmulationLogger.fine("Stopped advertising server");
}
}

0 comments on commit 5f9317e

Please sign in to comment.