|
@@ -6,10 +6,14 @@ import "package:flutter/cupertino.dart";
|
|
|
import 'package:flutter/material.dart';
|
|
|
import 'package:logging/logging.dart';
|
|
|
import 'package:photos/core/configuration.dart';
|
|
|
+import "package:photos/core/constants.dart";
|
|
|
import 'package:photos/core/event_bus.dart';
|
|
|
+import "package:photos/core/network/network.dart";
|
|
|
import "package:photos/db/files_db.dart";
|
|
|
import 'package:photos/events/subscription_purchased_event.dart';
|
|
|
+import "package:photos/gateways/cast_gw.dart";
|
|
|
import "package:photos/generated/l10n.dart";
|
|
|
+import "package:photos/l10n/l10n.dart";
|
|
|
import 'package:photos/models/backup_status.dart';
|
|
|
import 'package:photos/models/collection/collection.dart';
|
|
|
import 'package:photos/models/device_collection.dart';
|
|
@@ -36,6 +40,7 @@ import 'package:photos/utils/dialog_util.dart';
|
|
|
import 'package:photos/utils/magic_util.dart';
|
|
|
import 'package:photos/utils/navigation_util.dart';
|
|
|
import 'package:photos/utils/toast_util.dart';
|
|
|
+import "package:uuid/uuid.dart";
|
|
|
|
|
|
class GalleryAppBarWidget extends StatefulWidget {
|
|
|
final GalleryType type;
|
|
@@ -64,6 +69,7 @@ enum AlbumPopupAction {
|
|
|
ownedArchive,
|
|
|
sharedArchive,
|
|
|
ownedHide,
|
|
|
+ playOnTv,
|
|
|
sort,
|
|
|
leave,
|
|
|
freeUpSpace,
|
|
@@ -472,6 +478,22 @@ class _GalleryAppBarWidgetState extends State<GalleryAppBarWidget> {
|
|
|
),
|
|
|
);
|
|
|
}
|
|
|
+ if (widget.collection != null && isInternalUser) {
|
|
|
+ items.add(
|
|
|
+ PopupMenuItem(
|
|
|
+ value: AlbumPopupAction.playOnTv,
|
|
|
+ child: Row(
|
|
|
+ children: [
|
|
|
+ const Icon(Icons.tv_outlined),
|
|
|
+ const Padding(
|
|
|
+ padding: EdgeInsets.all(8),
|
|
|
+ ),
|
|
|
+ Text(context.l10n.playOnTv),
|
|
|
+ ],
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ );
|
|
|
+ }
|
|
|
|
|
|
if (galleryType.canDelete()) {
|
|
|
items.add(
|
|
@@ -579,6 +601,8 @@ class _GalleryAppBarWidgetState extends State<GalleryAppBarWidget> {
|
|
|
await _removeQuickLink();
|
|
|
} else if (value == AlbumPopupAction.leave) {
|
|
|
await _leaveAlbum(context);
|
|
|
+ } else if (value == AlbumPopupAction.playOnTv) {
|
|
|
+ await castAlbum();
|
|
|
} else if (value == AlbumPopupAction.freeUpSpace) {
|
|
|
await _deleteBackedUpFiles(context);
|
|
|
} else if (value == AlbumPopupAction.setCover) {
|
|
@@ -797,4 +821,40 @@ class _GalleryAppBarWidgetState extends State<GalleryAppBarWidget> {
|
|
|
);
|
|
|
setState(() {});
|
|
|
}
|
|
|
+
|
|
|
+ Future<void> castAlbum() async {
|
|
|
+ final gw = CastGateway(NetworkClient.instance.enteDio);
|
|
|
+ // stop any existing cast session
|
|
|
+ gw.revokeAllTokens().ignore();
|
|
|
+ await showTextInputDialog(
|
|
|
+ context,
|
|
|
+ title: context.l10n.playOnTv,
|
|
|
+ body: S.of(context).castInstruction,
|
|
|
+ submitButtonLabel: S.of(context).pair,
|
|
|
+ textInputType: TextInputType.streetAddress,
|
|
|
+ hintText: context.l10n.deviceCodeHint,
|
|
|
+ onSubmit: (String text) async {
|
|
|
+ try {
|
|
|
+ String code = text.trim();
|
|
|
+ final String? publicKey = await gw.getPublicKey(code);
|
|
|
+ if (publicKey == null) {
|
|
|
+ showToast(context, S.of(context).deviceNotFound);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ final String castToken = Uuid().v4().toString();
|
|
|
+ final castPayload = CollectionsService.instance
|
|
|
+ .getCastData(castToken, widget.collection!, publicKey);
|
|
|
+ await gw.publishCastPayload(
|
|
|
+ code,
|
|
|
+ castPayload,
|
|
|
+ widget.collection!.id,
|
|
|
+ castToken,
|
|
|
+ );
|
|
|
+ } catch (e, s) {
|
|
|
+ _logger.severe("Failed to cast album", e, s);
|
|
|
+ await showGenericErrorDialog(context: context, error: e);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ );
|
|
|
+ }
|
|
|
}
|