mirror of
https://github.com/KRTirtho/spotube.git
synced 2025-12-06 07:29:42 +00:00
Compare commits
6 Commits
6f3f571929
...
af8067bd92
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
af8067bd92 | ||
|
|
ca6924f5a9 | ||
|
|
42e954428b | ||
|
|
8c1337d1fc | ||
|
|
94e704087f | ||
|
|
8e287ab1e5 |
69
lib/components/dialogs/link_open_permission_dialog.dart
Normal file
69
lib/components/dialogs/link_open_permission_dialog.dart
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:shadcn_flutter/shadcn_flutter.dart';
|
||||||
|
import 'package:spotube/collections/spotube_icons.dart';
|
||||||
|
import 'package:spotube/extensions/context.dart';
|
||||||
|
import 'package:url_launcher/url_launcher_string.dart';
|
||||||
|
|
||||||
|
class LinkOpenPermissionDialog extends StatelessWidget {
|
||||||
|
final String? href;
|
||||||
|
const LinkOpenPermissionDialog({super.key, this.href});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return ConstrainedBox(
|
||||||
|
constraints: const BoxConstraints(maxWidth: 450),
|
||||||
|
child: AlertDialog(
|
||||||
|
title: Row(
|
||||||
|
spacing: 8,
|
||||||
|
children: [
|
||||||
|
const Icon(SpotubeIcons.warning),
|
||||||
|
Text(context.l10n.open_link_in_browser),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
content: Text.rich(
|
||||||
|
TextSpan(
|
||||||
|
children: [
|
||||||
|
TextSpan(
|
||||||
|
text:
|
||||||
|
"${context.l10n.do_you_want_to_open_the_following_link}:\n",
|
||||||
|
),
|
||||||
|
if (href != null)
|
||||||
|
TextSpan(
|
||||||
|
text: "$href\n\n",
|
||||||
|
style: const TextStyle(color: Colors.blue),
|
||||||
|
),
|
||||||
|
TextSpan(text: context.l10n.unsafe_url_warning),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
actions: [
|
||||||
|
Button.ghost(
|
||||||
|
onPressed: () => Navigator.of(context).pop(false),
|
||||||
|
child: Text(context.l10n.cancel),
|
||||||
|
),
|
||||||
|
Button.ghost(
|
||||||
|
onPressed: () {
|
||||||
|
if (href != null) {
|
||||||
|
Clipboard.setData(ClipboardData(text: href!));
|
||||||
|
}
|
||||||
|
Navigator.of(context).pop(false);
|
||||||
|
},
|
||||||
|
child: Text(context.l10n.copy_link),
|
||||||
|
),
|
||||||
|
Button.destructive(
|
||||||
|
onPressed: () {
|
||||||
|
if (href != null) {
|
||||||
|
launchUrlString(
|
||||||
|
href!,
|
||||||
|
mode: LaunchMode.externalApplication,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Navigator.of(context).pop(true);
|
||||||
|
},
|
||||||
|
child: Text(context.l10n.open),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,9 +1,7 @@
|
|||||||
import 'package:cached_network_image/cached_network_image.dart';
|
import 'package:cached_network_image/cached_network_image.dart';
|
||||||
import 'package:flutter/services.dart';
|
|
||||||
import 'package:flutter_markdown_plus/flutter_markdown_plus.dart';
|
import 'package:flutter_markdown_plus/flutter_markdown_plus.dart';
|
||||||
import 'package:shadcn_flutter/shadcn_flutter.dart';
|
import 'package:shadcn_flutter/shadcn_flutter.dart';
|
||||||
import 'package:spotube/collections/spotube_icons.dart';
|
import 'package:spotube/components/dialogs/link_open_permission_dialog.dart';
|
||||||
import 'package:spotube/extensions/context.dart';
|
|
||||||
import 'package:url_launcher/url_launcher_string.dart';
|
import 'package:url_launcher/url_launcher_string.dart';
|
||||||
|
|
||||||
class AppMarkdown extends StatelessWidget {
|
class AppMarkdown extends StatelessWidget {
|
||||||
@ -28,61 +26,7 @@ class AppMarkdown extends StatelessWidget {
|
|||||||
final allowOpeningLink = await showDialog<bool>(
|
final allowOpeningLink = await showDialog<bool>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (context) {
|
builder: (context) {
|
||||||
return ConstrainedBox(
|
return LinkOpenPermissionDialog(href: href);
|
||||||
constraints: const BoxConstraints(maxWidth: 450),
|
|
||||||
child: AlertDialog(
|
|
||||||
title: Row(
|
|
||||||
spacing: 8,
|
|
||||||
children: [
|
|
||||||
const Icon(SpotubeIcons.warning),
|
|
||||||
Text(context.l10n.open_link_in_browser),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
content: Text.rich(
|
|
||||||
TextSpan(
|
|
||||||
children: [
|
|
||||||
TextSpan(
|
|
||||||
text:
|
|
||||||
"${context.l10n.do_you_want_to_open_the_following_link}:\n",
|
|
||||||
),
|
|
||||||
if (href != null)
|
|
||||||
TextSpan(
|
|
||||||
text: "$href\n\n",
|
|
||||||
style: const TextStyle(color: Colors.blue),
|
|
||||||
),
|
|
||||||
TextSpan(text: context.l10n.unsafe_url_warning),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
actions: [
|
|
||||||
Button.ghost(
|
|
||||||
onPressed: () => Navigator.of(context).pop(false),
|
|
||||||
child: Text(context.l10n.cancel),
|
|
||||||
),
|
|
||||||
Button.ghost(
|
|
||||||
onPressed: () {
|
|
||||||
if (href != null) {
|
|
||||||
Clipboard.setData(ClipboardData(text: href));
|
|
||||||
}
|
|
||||||
Navigator.of(context).pop(false);
|
|
||||||
},
|
|
||||||
child: Text(context.l10n.copy_link),
|
|
||||||
),
|
|
||||||
Button.destructive(
|
|
||||||
onPressed: () {
|
|
||||||
if (href != null) {
|
|
||||||
launchUrlString(
|
|
||||||
href,
|
|
||||||
mode: LaunchMode.externalApplication,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Navigator.of(context).pop(true);
|
|
||||||
},
|
|
||||||
child: Text(context.l10n.open),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@ -461,5 +461,6 @@
|
|||||||
"available_plugins": "Available plugins",
|
"available_plugins": "Available plugins",
|
||||||
"configure_your_own_metadata_plugin": "Configure your own playlist/album/artist/feed metadata provider",
|
"configure_your_own_metadata_plugin": "Configure your own playlist/album/artist/feed metadata provider",
|
||||||
"audio_scrobblers": "Audio Scrobblers",
|
"audio_scrobblers": "Audio Scrobblers",
|
||||||
"scrobbling": "Scrobbling"
|
"scrobbling": "Scrobbling",
|
||||||
|
"source": "Source: "
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2930,6 +2930,12 @@ abstract class AppLocalizations {
|
|||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Scrobbling'**
|
/// **'Scrobbling'**
|
||||||
String get scrobbling;
|
String get scrobbling;
|
||||||
|
|
||||||
|
/// No description provided for @source.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Source: '**
|
||||||
|
String get source;
|
||||||
}
|
}
|
||||||
|
|
||||||
class _AppLocalizationsDelegate
|
class _AppLocalizationsDelegate
|
||||||
|
|||||||
@ -1537,4 +1537,7 @@ class AppLocalizationsAr extends AppLocalizations {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String get scrobbling => 'التتبع';
|
String get scrobbling => 'التتبع';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get source => 'Source: ';
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1538,4 +1538,7 @@ class AppLocalizationsBn extends AppLocalizations {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String get scrobbling => 'স্ক্রোব্বলিং';
|
String get scrobbling => 'স্ক্রোব্বলিং';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get source => 'Source: ';
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1548,4 +1548,7 @@ class AppLocalizationsCa extends AppLocalizations {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String get scrobbling => 'Scrobbling';
|
String get scrobbling => 'Scrobbling';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get source => 'Source: ';
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1538,4 +1538,7 @@ class AppLocalizationsCs extends AppLocalizations {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String get scrobbling => 'Scrobbling';
|
String get scrobbling => 'Scrobbling';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get source => 'Source: ';
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1550,4 +1550,7 @@ class AppLocalizationsDe extends AppLocalizations {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String get scrobbling => 'Scrobbling';
|
String get scrobbling => 'Scrobbling';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get source => 'Source: ';
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1536,4 +1536,7 @@ class AppLocalizationsEn extends AppLocalizations {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String get scrobbling => 'Scrobbling';
|
String get scrobbling => 'Scrobbling';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get source => 'Source: ';
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1551,4 +1551,7 @@ class AppLocalizationsEs extends AppLocalizations {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String get scrobbling => 'Scrobbling';
|
String get scrobbling => 'Scrobbling';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get source => 'Source: ';
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1548,4 +1548,7 @@ class AppLocalizationsEu extends AppLocalizations {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String get scrobbling => 'Scrobbling';
|
String get scrobbling => 'Scrobbling';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get source => 'Source: ';
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1536,4 +1536,7 @@ class AppLocalizationsFa extends AppLocalizations {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String get scrobbling => 'اسکراببلینگ';
|
String get scrobbling => 'اسکراببلینگ';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get source => 'Source: ';
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1536,4 +1536,7 @@ class AppLocalizationsFi extends AppLocalizations {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String get scrobbling => 'Scrobbling';
|
String get scrobbling => 'Scrobbling';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get source => 'Source: ';
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1556,4 +1556,7 @@ class AppLocalizationsFr extends AppLocalizations {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String get scrobbling => 'Scrobbling';
|
String get scrobbling => 'Scrobbling';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get source => 'Source: ';
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1542,4 +1542,7 @@ class AppLocalizationsHi extends AppLocalizations {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String get scrobbling => 'स्क्रॉबलिंग';
|
String get scrobbling => 'स्क्रॉबलिंग';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get source => 'Source: ';
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1544,4 +1544,7 @@ class AppLocalizationsId extends AppLocalizations {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String get scrobbling => 'Scrobbling';
|
String get scrobbling => 'Scrobbling';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get source => 'Source: ';
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1543,4 +1543,7 @@ class AppLocalizationsIt extends AppLocalizations {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String get scrobbling => 'Scrobbling';
|
String get scrobbling => 'Scrobbling';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get source => 'Source: ';
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1507,4 +1507,7 @@ class AppLocalizationsJa extends AppLocalizations {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String get scrobbling => 'Scrobbling';
|
String get scrobbling => 'Scrobbling';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get source => 'Source: ';
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1545,4 +1545,7 @@ class AppLocalizationsKa extends AppLocalizations {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String get scrobbling => 'სქრობლინგი';
|
String get scrobbling => 'სქრობლინგი';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get source => 'Source: ';
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1511,4 +1511,7 @@ class AppLocalizationsKo extends AppLocalizations {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String get scrobbling => '스크로블링';
|
String get scrobbling => '스크로블링';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get source => 'Source: ';
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1548,4 +1548,7 @@ class AppLocalizationsNe extends AppLocalizations {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String get scrobbling => 'स्क्रब्बलिंग';
|
String get scrobbling => 'स्क्रब्बलिंग';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get source => 'Source: ';
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1542,4 +1542,7 @@ class AppLocalizationsNl extends AppLocalizations {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String get scrobbling => 'Scrobbling';
|
String get scrobbling => 'Scrobbling';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get source => 'Source: ';
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1544,4 +1544,7 @@ class AppLocalizationsPl extends AppLocalizations {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String get scrobbling => 'Scrobbling';
|
String get scrobbling => 'Scrobbling';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get source => 'Source: ';
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1541,4 +1541,7 @@ class AppLocalizationsPt extends AppLocalizations {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String get scrobbling => 'Scrobbling';
|
String get scrobbling => 'Scrobbling';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get source => 'Source: ';
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1544,4 +1544,7 @@ class AppLocalizationsRu extends AppLocalizations {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String get scrobbling => 'Скробблинг';
|
String get scrobbling => 'Скробблинг';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get source => 'Source: ';
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1550,4 +1550,7 @@ class AppLocalizationsTa extends AppLocalizations {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String get scrobbling => 'ஸ்க்ரோப்ளிங்';
|
String get scrobbling => 'ஸ்க்ரோப்ளிங்';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get source => 'Source: ';
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1533,4 +1533,7 @@ class AppLocalizationsTh extends AppLocalizations {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String get scrobbling => 'Scrobbling';
|
String get scrobbling => 'Scrobbling';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get source => 'Source: ';
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1551,4 +1551,7 @@ class AppLocalizationsTl extends AppLocalizations {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String get scrobbling => 'Scrobbling';
|
String get scrobbling => 'Scrobbling';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get source => 'Source: ';
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1544,4 +1544,7 @@ class AppLocalizationsTr extends AppLocalizations {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String get scrobbling => 'Scrobbling';
|
String get scrobbling => 'Scrobbling';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get source => 'Source: ';
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1540,4 +1540,7 @@ class AppLocalizationsUk extends AppLocalizations {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String get scrobbling => 'Скроблінг';
|
String get scrobbling => 'Скроблінг';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get source => 'Source: ';
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1546,4 +1546,7 @@ class AppLocalizationsVi extends AppLocalizations {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String get scrobbling => 'Scrobbling';
|
String get scrobbling => 'Scrobbling';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get source => 'Source: ';
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1500,6 +1500,9 @@ class AppLocalizationsZh extends AppLocalizations {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String get scrobbling => 'Scrobbling';
|
String get scrobbling => 'Scrobbling';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get source => 'Source: ';
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The translations for Chinese, as used in Taiwan (`zh_TW`).
|
/// The translations for Chinese, as used in Taiwan (`zh_TW`).
|
||||||
|
|||||||
@ -20,17 +20,20 @@ class HomeRecentlyPlayedSection extends HookConsumerWidget {
|
|||||||
return const SizedBox();
|
return const SizedBox();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final uniqueItems = <dynamic>{};
|
||||||
|
final filteredItems = [
|
||||||
|
for (final item in historyData)
|
||||||
|
if (item.playlist != null && item.playlist?.id != null && uniqueItems.add(item.playlist!.id!))
|
||||||
|
item.playlist
|
||||||
|
else if (item.album != null && item.album?.id != null && uniqueItems.add(item.album?.id))
|
||||||
|
item.album
|
||||||
|
];
|
||||||
|
|
||||||
return Skeletonizer(
|
return Skeletonizer(
|
||||||
enabled: history.isLoading,
|
enabled: history.isLoading,
|
||||||
child: HorizontalPlaybuttonCardView(
|
child: HorizontalPlaybuttonCardView(
|
||||||
title: Text(context.l10n.recently_played),
|
title: Text(context.l10n.recently_played),
|
||||||
items: [
|
items: filteredItems,
|
||||||
for (final item in historyData)
|
|
||||||
if (item.playlist != null)
|
|
||||||
item.playlist
|
|
||||||
else if (item.album != null)
|
|
||||||
item.album
|
|
||||||
],
|
|
||||||
hasNextPage: false,
|
hasNextPage: false,
|
||||||
isLoadingNextPage: false,
|
isLoadingNextPage: false,
|
||||||
onFetchMore: () {},
|
onFetchMore: () {},
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
import 'package:flutter/gestures.dart';
|
||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:shadcn_flutter/shadcn_flutter.dart';
|
import 'package:shadcn_flutter/shadcn_flutter.dart';
|
||||||
@ -8,6 +9,7 @@ import 'package:spotube/extensions/context.dart';
|
|||||||
import 'package:spotube/models/metadata/metadata.dart';
|
import 'package:spotube/models/metadata/metadata.dart';
|
||||||
import 'package:spotube/provider/metadata_plugin/metadata_plugin_provider.dart';
|
import 'package:spotube/provider/metadata_plugin/metadata_plugin_provider.dart';
|
||||||
import 'package:url_launcher/url_launcher_string.dart';
|
import 'package:url_launcher/url_launcher_string.dart';
|
||||||
|
import 'package:change_case/change_case.dart';
|
||||||
|
|
||||||
class MetadataPluginRepositoryItem extends HookConsumerWidget {
|
class MetadataPluginRepositoryItem extends HookConsumerWidget {
|
||||||
final MetadataPluginRepository pluginRepo;
|
final MetadataPluginRepository pluginRepo;
|
||||||
@ -26,43 +28,21 @@ class MetadataPluginRepositoryItem extends HookConsumerWidget {
|
|||||||
final isInstalling = useState(false);
|
final isInstalling = useState(false);
|
||||||
|
|
||||||
return Card(
|
return Card(
|
||||||
child: Basic(
|
child: Column(
|
||||||
title: Text(
|
|
||||||
"${pluginRepo.owner == "KRTirtho" ? "" : "${pluginRepo.owner}/"}${pluginRepo.name}"),
|
|
||||||
subtitle: Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
spacing: 8,
|
spacing: 8,
|
||||||
children: [
|
children: [
|
||||||
Text(pluginRepo.description),
|
Basic(
|
||||||
Row(
|
title: Text(
|
||||||
spacing: 8,
|
pluginRepo.name.startsWith("spotube-plugin")
|
||||||
children: [
|
? pluginRepo.name
|
||||||
if (pluginRepo.owner == "KRTirtho") ...[
|
.replaceFirst("spotube-plugin-", "")
|
||||||
PrimaryBadge(
|
.trim()
|
||||||
leading: Icon(SpotubeIcons.done),
|
.toCapitalCase()
|
||||||
child: Text(context.l10n.official),
|
: pluginRepo.name.toCapitalCase(),
|
||||||
),
|
|
||||||
SecondaryBadge(
|
|
||||||
leading: host == "github.com"
|
|
||||||
? const Icon(SpotubeIcons.github)
|
|
||||||
: null,
|
|
||||||
child: Text(host),
|
|
||||||
onPressed: () {
|
|
||||||
launchUrlString(pluginRepo.repoUrl);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
] else ...[
|
|
||||||
Text(context.l10n.author_name(pluginRepo.owner)),
|
|
||||||
DestructiveBadge(
|
|
||||||
leading: const Icon(SpotubeIcons.warning),
|
|
||||||
child: Text(context.l10n.third_party),
|
|
||||||
)
|
|
||||||
]
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
|
subtitle: Text(pluginRepo.description),
|
||||||
trailing: Button.primary(
|
trailing: Button.primary(
|
||||||
enabled: !isInstalling.value,
|
enabled: !isInstalling.value,
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
@ -80,13 +60,13 @@ class MetadataPluginRepositoryItem extends HookConsumerWidget {
|
|||||||
context: context,
|
context: context,
|
||||||
builder: (context) {
|
builder: (context) {
|
||||||
final pluginAbilities = pluginConfig.apis
|
final pluginAbilities = pluginConfig.apis
|
||||||
.map(
|
.map((e) =>
|
||||||
(e) => context.l10n.can_access_name_api(e.name))
|
context.l10n.can_access_name_api(e.name))
|
||||||
.join("\n\n");
|
.join("\n\n");
|
||||||
|
|
||||||
return AlertDialog(
|
return AlertDialog(
|
||||||
title: Text(
|
title: Text(context
|
||||||
context.l10n.do_you_want_to_install_this_plugin),
|
.l10n.do_you_want_to_install_this_plugin),
|
||||||
content: Column(
|
content: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
@ -95,8 +75,8 @@ class MetadataPluginRepositoryItem extends HookConsumerWidget {
|
|||||||
Text(context.l10n.third_party_plugin_warning),
|
Text(context.l10n.third_party_plugin_warning),
|
||||||
const Gap(8),
|
const Gap(8),
|
||||||
FutureBuilder(
|
FutureBuilder(
|
||||||
future:
|
future: pluginsNotifier
|
||||||
pluginsNotifier.getLogoPath(pluginConfig),
|
.getLogoPath(pluginConfig),
|
||||||
builder: (context, snapshot) {
|
builder: (context, snapshot) {
|
||||||
return Basic(
|
return Basic(
|
||||||
leading: snapshot.hasData
|
leading: snapshot.hasData
|
||||||
@ -110,16 +90,17 @@ class MetadataPluginRepositoryItem extends HookConsumerWidget {
|
|||||||
width: 36,
|
width: 36,
|
||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: context
|
color: context.theme
|
||||||
.theme.colorScheme.secondary,
|
.colorScheme.secondary,
|
||||||
borderRadius:
|
borderRadius:
|
||||||
BorderRadius.circular(8),
|
BorderRadius.circular(8),
|
||||||
),
|
),
|
||||||
child:
|
child: const Icon(
|
||||||
const Icon(SpotubeIcons.plugin),
|
SpotubeIcons.plugin),
|
||||||
),
|
),
|
||||||
title: Text(pluginConfig.name),
|
title: Text(pluginConfig.name),
|
||||||
subtitle: Text(pluginConfig.description),
|
subtitle:
|
||||||
|
Text(pluginConfig.description),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@ -160,11 +141,68 @@ class MetadataPluginRepositoryItem extends HookConsumerWidget {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
leading: isInstalling.value
|
leading: isInstalling.value
|
||||||
? const CircularProgressIndicator()
|
? SizedBox.square(
|
||||||
|
dimension: 20,
|
||||||
|
child: CircularProgressIndicator(
|
||||||
|
color: context.theme.colorScheme.primaryForeground,
|
||||||
|
),
|
||||||
|
)
|
||||||
: const Icon(SpotubeIcons.add),
|
: const Icon(SpotubeIcons.add),
|
||||||
child: Text(context.l10n.install),
|
child: Text(context.l10n.install),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
if (pluginRepo.owner != "KRTirtho")
|
||||||
|
Text.rich(
|
||||||
|
TextSpan(
|
||||||
|
children: [
|
||||||
|
TextSpan(text: context.l10n.source),
|
||||||
|
TextSpan(
|
||||||
|
text: pluginRepo.repoUrl.replaceAll("https://", ""),
|
||||||
|
style: const TextStyle(
|
||||||
|
color: Colors.blue,
|
||||||
|
decoration: TextDecoration.underline,
|
||||||
|
),
|
||||||
|
recognizer: TapGestureRecognizer()
|
||||||
|
..onTap = () async {
|
||||||
|
launchUrlString(pluginRepo.repoUrl);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
style: context.theme.typography.xSmall,
|
||||||
|
),
|
||||||
|
Wrap(
|
||||||
|
spacing: 8,
|
||||||
|
runSpacing: 8,
|
||||||
|
children: [
|
||||||
|
if (pluginRepo.owner == "KRTirtho")
|
||||||
|
PrimaryBadge(
|
||||||
|
leading: const Icon(SpotubeIcons.done),
|
||||||
|
child: Text(context.l10n.official),
|
||||||
|
)
|
||||||
|
else ...[
|
||||||
|
Text(
|
||||||
|
context.l10n.author_name(pluginRepo.owner),
|
||||||
|
style: context.theme.typography.xSmall,
|
||||||
|
),
|
||||||
|
DestructiveBadge(
|
||||||
|
leading: const Icon(SpotubeIcons.warning),
|
||||||
|
child: Text(context.l10n.third_party),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
SecondaryBadge(
|
||||||
|
leading: host == "github.com"
|
||||||
|
? const Icon(SpotubeIcons.github)
|
||||||
|
: null,
|
||||||
|
child: Text(host),
|
||||||
|
onPressed: () {
|
||||||
|
launchUrlString(pluginRepo.repoUrl);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -350,6 +350,8 @@ class MetadataPluginNotifier extends AsyncNotifier<MetadataPluginState> {
|
|||||||
abilities: plugin.abilities.map((e) => e.name).toList(),
|
abilities: plugin.abilities.map((e) => e.name).toList(),
|
||||||
pluginApiVersion: Value(plugin.pluginApiVersion),
|
pluginApiVersion: Value(plugin.pluginApiVersion),
|
||||||
repository: Value(plugin.repository),
|
repository: Value(plugin.repository),
|
||||||
|
// Setting the very first plugin as the default plugin
|
||||||
|
selected: Value(state.valueOrNull?.plugins.isEmpty ?? true),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -362,6 +364,17 @@ class MetadataPluginNotifier extends AsyncNotifier<MetadataPluginState> {
|
|||||||
}
|
}
|
||||||
await database.metadataPluginsTable.deleteWhere((tbl) =>
|
await database.metadataPluginsTable.deleteWhere((tbl) =>
|
||||||
tbl.name.equals(plugin.name) & tbl.author.equals(plugin.author));
|
tbl.name.equals(plugin.name) & tbl.author.equals(plugin.author));
|
||||||
|
|
||||||
|
// Same here, if the removed plugin is the default plugin
|
||||||
|
// set the first available plugin as the default plugin
|
||||||
|
// only when there is 1 remaining plugin
|
||||||
|
if (state.valueOrNull?.defaultPluginConfig == plugin) {
|
||||||
|
final remainingPlugins =
|
||||||
|
state.valueOrNull?.plugins.where((p) => p != plugin) ?? [];
|
||||||
|
if (remainingPlugins.length == 1) {
|
||||||
|
await setDefaultPlugin(remainingPlugins.first);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> updatePlugin(
|
Future<void> updatePlugin(
|
||||||
|
|||||||
@ -315,7 +315,7 @@ packages:
|
|||||||
source: hosted
|
source: hosted
|
||||||
version: "1.3.1"
|
version: "1.3.1"
|
||||||
change_case:
|
change_case:
|
||||||
dependency: transitive
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: change_case
|
name: change_case
|
||||||
sha256: f4e08feaa845e75e4f5ad2b0e15f24813d7ea6c27e7b78252f0c17f752cf1157
|
sha256: f4e08feaa845e75e4f5ad2b0e15f24813d7ea6c27e7b78252f0c17f752cf1157
|
||||||
|
|||||||
@ -163,6 +163,7 @@ dependencies:
|
|||||||
get_it: ^8.0.3
|
get_it: ^8.0.3
|
||||||
flutter_markdown_plus: ^1.0.3
|
flutter_markdown_plus: ^1.0.3
|
||||||
pub_semver: ^2.2.0
|
pub_semver: ^2.2.0
|
||||||
|
change_case: ^1.1.0
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
build_runner: ^2.4.13
|
build_runner: ^2.4.13
|
||||||
|
|||||||
@ -1,5 +1,118 @@
|
|||||||
{
|
{
|
||||||
|
"ar": [
|
||||||
|
"source"
|
||||||
|
],
|
||||||
|
|
||||||
|
"bn": [
|
||||||
|
"source"
|
||||||
|
],
|
||||||
|
|
||||||
|
"ca": [
|
||||||
|
"source"
|
||||||
|
],
|
||||||
|
|
||||||
|
"cs": [
|
||||||
|
"source"
|
||||||
|
],
|
||||||
|
|
||||||
|
"de": [
|
||||||
|
"source"
|
||||||
|
],
|
||||||
|
|
||||||
|
"es": [
|
||||||
|
"source"
|
||||||
|
],
|
||||||
|
|
||||||
|
"eu": [
|
||||||
|
"source"
|
||||||
|
],
|
||||||
|
|
||||||
|
"fa": [
|
||||||
|
"source"
|
||||||
|
],
|
||||||
|
|
||||||
|
"fi": [
|
||||||
|
"source"
|
||||||
|
],
|
||||||
|
|
||||||
|
"fr": [
|
||||||
|
"source"
|
||||||
|
],
|
||||||
|
|
||||||
|
"hi": [
|
||||||
|
"source"
|
||||||
|
],
|
||||||
|
|
||||||
|
"id": [
|
||||||
|
"source"
|
||||||
|
],
|
||||||
|
|
||||||
|
"it": [
|
||||||
|
"source"
|
||||||
|
],
|
||||||
|
|
||||||
|
"ja": [
|
||||||
|
"source"
|
||||||
|
],
|
||||||
|
|
||||||
|
"ka": [
|
||||||
|
"source"
|
||||||
|
],
|
||||||
|
|
||||||
|
"ko": [
|
||||||
|
"source"
|
||||||
|
],
|
||||||
|
|
||||||
|
"ne": [
|
||||||
|
"source"
|
||||||
|
],
|
||||||
|
|
||||||
"nl": [
|
"nl": [
|
||||||
"audio_source"
|
"audio_source",
|
||||||
|
"source"
|
||||||
|
],
|
||||||
|
|
||||||
|
"pl": [
|
||||||
|
"source"
|
||||||
|
],
|
||||||
|
|
||||||
|
"pt": [
|
||||||
|
"source"
|
||||||
|
],
|
||||||
|
|
||||||
|
"ru": [
|
||||||
|
"source"
|
||||||
|
],
|
||||||
|
|
||||||
|
"ta": [
|
||||||
|
"source"
|
||||||
|
],
|
||||||
|
|
||||||
|
"th": [
|
||||||
|
"source"
|
||||||
|
],
|
||||||
|
|
||||||
|
"tl": [
|
||||||
|
"source"
|
||||||
|
],
|
||||||
|
|
||||||
|
"tr": [
|
||||||
|
"source"
|
||||||
|
],
|
||||||
|
|
||||||
|
"uk": [
|
||||||
|
"source"
|
||||||
|
],
|
||||||
|
|
||||||
|
"vi": [
|
||||||
|
"source"
|
||||||
|
],
|
||||||
|
|
||||||
|
"zh": [
|
||||||
|
"source"
|
||||||
|
],
|
||||||
|
|
||||||
|
"zh_TW": [
|
||||||
|
"source"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user