diff --git a/app/torrent/[hash].tsx b/app/torrent/[hash].tsx
index 1aca037..2340e70 100644
--- a/app/torrent/[hash].tsx
+++ b/app/torrent/[hash].tsx
@@ -423,6 +423,7 @@ export default function TorrentDetail() {
await new Promise(resolve => setTimeout(resolve, 250));
await loadTorrentData();
setActionLoading(false);
+ showToast('Reannounce sent', 'success');
} catch (error: any) {
showToast(error.message || 'Failed to reannounce torrent', 'error');
setActionLoading(false);
@@ -649,61 +650,59 @@ export default function TorrentDetail() {
);
};
- const handleAddTags = () => {
- Alert.prompt(
- 'Add Tags',
- 'Enter tags (comma-separated)',
- [
- { text: 'Cancel', style: 'cancel' },
- {
- text: 'Add',
- onPress: async (value: string | undefined) => {
- if (!value || value.trim() === '') return;
- try {
- setActionLoading(true);
- const tags = value.split(',').map((tag: string) => tag.trim()).filter((tag: string) => tag !== '');
- await torrentsApi.addTorrentTags([torrent.hash], tags);
- await new Promise(resolve => setTimeout(resolve, 500));
- await loadTorrentData();
- showToast(`Added ${tags.length} tag(s)`, 'success');
- } catch (error: any) {
- showToast(error.message || 'Failed to add tags', 'error');
- } finally {
- setActionLoading(false);
- }
- },
+ const handleManageTags = () => {
+ const currentTags = torrent.tags ? torrent.tags.split(',').map((t: string) => t.trim()).filter(Boolean) : [];
+
+ const options: Array<{ text: string; style?: 'cancel' | 'default' | 'destructive'; onPress?: () => void }> = [
+ ...currentTags.map(tag => ({
+ text: `✕ ${tag}`,
+ onPress: async () => {
+ try {
+ setActionLoading(true);
+ await torrentsApi.removeTorrentTags([torrent.hash], [tag]);
+ await new Promise(resolve => setTimeout(resolve, 500));
+ await loadTorrentData();
+ showToast(`Removed tag "${tag}"`, 'success');
+ } catch (error: any) {
+ showToast(error.message || 'Failed to remove tag', 'error');
+ } finally {
+ setActionLoading(false);
+ }
},
- ],
- 'plain-text'
- );
- };
-
- const handleRemoveTags = () => {
- Alert.prompt(
- 'Remove Tags',
- 'Enter tags to remove (comma-separated)',
- [
- { text: 'Cancel', style: 'cancel' },
- {
- text: 'Remove',
- onPress: async (value: string | undefined) => {
- if (!value || value.trim() === '') return;
- try {
- setActionLoading(true);
- const tags = value.split(',').map((tag: string) => tag.trim()).filter((tag: string) => tag !== '');
- await torrentsApi.removeTorrentTags([torrent.hash], tags);
- await new Promise(resolve => setTimeout(resolve, 500));
- await loadTorrentData();
- showToast(`Removed ${tags.length} tag(s)`, 'success');
- } catch (error: any) {
- showToast(error.message || 'Failed to remove tags', 'error');
- } finally {
- setActionLoading(false);
- }
- },
+ })),
+ {
+ text: '+ Add Tags',
+ onPress: () => {
+ Alert.prompt('Add Tags', 'Enter tags (comma-separated)', [
+ { text: 'Cancel', style: 'cancel' },
+ {
+ text: 'Add',
+ onPress: async (value: string | undefined) => {
+ if (!value || !value.trim()) return;
+ try {
+ setActionLoading(true);
+ const tags = value.split(',').map((t: string) => t.trim()).filter(Boolean);
+ await torrentsApi.addTorrentTags([torrent.hash], tags);
+ await new Promise(resolve => setTimeout(resolve, 500));
+ await loadTorrentData();
+ showToast(`Added ${tags.length} tag(s)`, 'success');
+ } catch (error: any) {
+ showToast(error.message || 'Failed to add tags', 'error');
+ } finally {
+ setActionLoading(false);
+ }
+ },
+ },
+ ], 'plain-text');
},
- ],
- 'plain-text'
+ },
+ { text: 'Cancel', style: 'cancel' },
+ ];
+
+ Alert.alert(
+ 'Manage Tags',
+ currentTags.length > 0 ? 'Tap a tag to remove it' : 'No tags assigned',
+ options
);
};
@@ -826,14 +825,6 @@ export default function TorrentDetail() {
Recheck
-
-
- Reannounce
-
router.push(`/torrent/files?hash=${hash}`)}
@@ -881,11 +872,13 @@ export default function TorrentDetail() {
{properties.save_path}
-
+
Category
-
- {torrent.category || 'None'}
-
+
+
+ {torrent.category || 'None'}
+
+
Tags
@@ -1067,40 +1060,40 @@ export default function TorrentDetail() {
{/* Priority Controls */}
- {torrent?.force_start ? 'Force Start ON' : 'Force Start'}
+ {torrent.force_start ? 'Force Start ✓' : 'Force Start'}
- {torrent?.super_seeding ? 'Super Seed ON' : 'Super Seed'}
+ {torrent.super_seeding ? 'Super Seed ✓' : 'Super Seed'}
- Sequential DL
+ {torrent.seq_dl ? 'Sequential DL ✓' : 'Sequential DL'}
- First/Last Priority
+ {torrent.f_l_piece_prio ? 'First/Last Piece ✓' : 'First/Last Piece'}
@@ -1157,14 +1150,23 @@ export default function TorrentDetail() {
{/* Trackers & Metadata */}
-
-
- Edit Trackers
-
+
+
+
+
+
+
+ Trackers
+
+
{/* Category & Tags */}
- Add Tags
-
-
-
- Remove Tags
+ Tags
{/* Location & Rename */}
@@ -1358,6 +1352,15 @@ const styles = StyleSheet.create({
infoRowWithButton: {
position: 'relative',
},
+ categoryBadge: {
+ paddingHorizontal: 10,
+ paddingVertical: 4,
+ borderRadius: 12,
+ },
+ categoryBadgeText: {
+ fontSize: 13,
+ fontWeight: '600',
+ },
peersInfoBtn: {
marginLeft: 8,
padding: 4,
@@ -1453,6 +1456,18 @@ const styles = StyleSheet.create({
gap: 6,
marginTop: 6,
},
+ advancedToolFullRow: {
+ flexDirection: 'row',
+ width: '100%',
+ gap: 6,
+ },
+ reannounceIconButton: {
+ width: 44,
+ borderRadius: 10,
+ alignItems: 'center',
+ justifyContent: 'center',
+ paddingVertical: 8,
+ },
advancedToolButton: {
flex: 1,
minWidth: '47%',