Skip to content

Commit e94aaee

Browse files
authored
Update WallpaperGrid.tsx
1 parent 1327f3f commit e94aaee

1 file changed

Lines changed: 141 additions & 73 deletions

File tree

Lines changed: 141 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -1,90 +1,158 @@
11
import React, { useState } from 'react';
2-
import { Download, X, Maximize2 } from 'lucide-react';
2+
import { Download, X, Maximize2, Loader2, CheckCircle, AlertCircle } from 'lucide-react';
33
import { WALLPAPERS } from '../constants';
4-
import { Wallpaper } from '../types';
4+
import { Wallpaper, Language } from '../types';
5+
import { Filesystem, Directory } from '@capacitor/filesystem';
6+
import { Toast } from '@capacitor/toast';
7+
import { TRANSLATIONS } from '../utils/translations';
58

6-
export const WallpaperGrid: React.FC = () => {
9+
interface WallpaperGridProps {
10+
language: Language;
11+
}
12+
13+
export const WallpaperGrid: React.FC<WallpaperGridProps> = ({ language }) => {
714
const [selectedWallpaper, setSelectedWallpaper] = useState<Wallpaper | null>(null);
15+
const [downloading, setDownloading] = useState(false);
16+
const t = TRANSLATIONS[language];
817

9-
const handleDownload = (url: string, name: string) => {
10-
const link = document.createElement('a');
11-
link.href = url;
12-
link.target = '_blank';
13-
link.download = `${name.replace(/\s+/g, '-')}.png`;
14-
document.body.appendChild(link);
15-
link.click();
16-
document.body.removeChild(link);
17-
};
18+
const handleDownload = async (url: string, name: string) => {
19+
setDownloading(true);
20+
try {
21+
// 1. Fetch the blob
22+
const response = await fetch(url);
23+
const blob = await response.blob();
1824

19-
return (
20-
<div className="pb-24 pt-2">
21-
<div className="px-6 mb-6">
22-
<h2 className="text-3xl font-mono font-bold text-white mb-1">WALLPAPERS</h2>
23-
<p className="text-muted text-sm">Customize your device</p>
24-
</div>
25+
// 2. Convert to base64
26+
const reader = new FileReader();
27+
reader.readAsDataURL(blob);
28+
reader.onloadend = async () => {
29+
const base64data = reader.result as string;
30+
31+
try {
32+
// 3. Try Capacitor Filesystem
33+
const fileName = `HackerOS_${name.replace(/\s+/g, '_')}_${Date.now()}.png`;
34+
35+
await Filesystem.writeFile({
36+
path: fileName,
37+
data: base64data,
38+
directory: Directory.Documents
39+
});
40+
41+
await Toast.show({
42+
text: `Wallpaper saved to Documents/${fileName}`,
43+
duration: 'long'
44+
});
45+
46+
} catch (fsError) {
47+
console.error("Filesystem write failed, falling back to browser download", fsError);
48+
49+
// Fallback: Create generic anchor click (standard browser behavior)
50+
const link = document.createElement('a');
51+
link.href = base64data;
52+
link.download = `${name.replace(/\s+/g, '-')}.png`;
53+
document.body.appendChild(link);
54+
link.click();
55+
document.body.removeChild(link);
2556

26-
<div className="grid grid-cols-2 gap-4 px-4">
27-
{WALLPAPERS.map((wp) => (
28-
<button
29-
key={wp.id}
30-
onClick={() => setSelectedWallpaper(wp)}
31-
className="group relative aspect-[9/16] rounded-2xl overflow-hidden shadow-lg border border-white/5 bg-card/30"
32-
>
33-
<img
34-
src={wp.thumbnail}
35-
alt={wp.name}
36-
className="w-full h-full object-cover transition-transform duration-700 group-hover:scale-105"
37-
loading="lazy"
38-
/>
57+
await Toast.show({
58+
text: `Download started...`,
59+
duration: 'short'
60+
});
61+
}
62+
setDownloading(false);
63+
};
3964

40-
{/* Overlay Gradient */}
41-
<div className="absolute inset-0 bg-gradient-to-t from-background via-transparent to-transparent opacity-80" />
65+
} catch (error) {
66+
console.error('Download failed:', error);
67+
await Toast.show({
68+
text: 'Download failed. Check internet connection.',
69+
duration: 'short'
70+
});
71+
setDownloading(false);
72+
}
73+
};
4274

43-
<div className="absolute bottom-0 left-0 right-0 p-4 text-left">
44-
<span className="text-white text-sm font-bold block mb-1 drop-shadow-md">{wp.name}</span>
45-
<div className="flex items-center gap-1 text-[10px] text-primary font-mono bg-black/40 backdrop-blur-sm px-2 py-0.5 rounded w-fit">
46-
<Maximize2 size={10} />
47-
<span>HD_ASSET</span>
75+
return (
76+
<div className="pb-24 pt-2">
77+
<div className="px-6 mb-6">
78+
<h2 className="text-3xl font-mono font-bold text-white mb-1">{t.header_wallpapers}</h2>
79+
<p className="text-muted text-sm">{t.sub_wallpapers}</p>
4880
</div>
81+
82+
<div className="grid grid-cols-2 gap-4 px-4">
83+
{WALLPAPERS.map((wp) => (
84+
<button
85+
key={wp.id}
86+
onClick={() => setSelectedWallpaper(wp)}
87+
className="group relative aspect-[9/16] rounded-2xl overflow-hidden shadow-lg border border-white/5 bg-card/30"
88+
>
89+
<img
90+
src={wp.thumbnail}
91+
alt={wp.name}
92+
className="w-full h-full object-cover transition-transform duration-700 group-hover:scale-105"
93+
loading="lazy"
94+
/>
95+
96+
{/* Overlay Gradient */}
97+
<div className="absolute inset-0 bg-gradient-to-t from-background via-transparent to-transparent opacity-80" />
98+
99+
<div className="absolute bottom-0 left-0 right-0 p-4 text-left">
100+
<span className="text-white text-sm font-bold block mb-1 drop-shadow-md">{wp.name}</span>
101+
<div className="flex items-center gap-1 text-[10px] text-primary font-mono bg-black/40 backdrop-blur-sm px-2 py-0.5 rounded w-fit">
102+
<Maximize2 size={10} />
103+
<span>{t.hd_asset}</span>
104+
</div>
105+
</div>
106+
</button>
107+
))}
49108
</div>
50-
</button>
51-
))}
52-
</div>
53109

54-
{/* Fullscreen Preview Modal */}
55-
{selectedWallpaper && (
56-
<div className="fixed inset-0 z-[100] flex items-center justify-center bg-black/95 backdrop-blur-xl p-0 animate-in fade-in duration-200">
57-
<button
58-
onClick={() => setSelectedWallpaper(null)}
59-
className="absolute top-8 right-6 p-3 text-white/70 hover:text-white rounded-full bg-white/10 z-10 backdrop-blur-md"
60-
>
61-
<X size={24} />
62-
</button>
110+
{/* Fullscreen Preview Modal */}
111+
{selectedWallpaper && (
112+
<div className="fixed inset-0 z-[100] flex items-center justify-center bg-black/95 backdrop-blur-xl p-0 animate-in fade-in duration-200">
113+
<button
114+
onClick={() => setSelectedWallpaper(null)}
115+
className="absolute top-8 right-6 p-3 text-white/70 hover:text-white rounded-full bg-white/10 z-10 backdrop-blur-md"
116+
>
117+
<X size={24} />
118+
</button>
63119

64-
<div className="relative w-full h-full flex flex-col items-center justify-center">
65-
<div className="relative w-full max-w-[85vw] aspect-[9/16] rounded-2xl overflow-hidden shadow-[0_0_50px_-12px_rgba(var(--color-primary),0.3)] border border-white/10">
66-
<img
67-
src={selectedWallpaper.url}
68-
alt={selectedWallpaper.name}
69-
className="w-full h-full object-cover"
70-
/>
71-
</div>
120+
<div className="relative w-full h-full flex flex-col items-center justify-center">
121+
<div className="relative w-full max-w-[85vw] aspect-[9/16] rounded-2xl overflow-hidden shadow-[0_0_50px_-12px_rgba(var(--color-primary),0.3)] border border-white/10">
122+
<img
123+
src={selectedWallpaper.url}
124+
alt={selectedWallpaper.name}
125+
className="w-full h-full object-cover"
126+
/>
127+
</div>
72128

73-
<div className="absolute bottom-12 w-full px-8">
74-
<button
75-
onClick={(e) => {
76-
e.stopPropagation();
77-
handleDownload(selectedWallpaper.url, selectedWallpaper.name);
78-
}}
79-
className="w-full flex items-center justify-center gap-3 bg-primary hover:bg-primary/90 text-background px-6 py-4 rounded-xl font-bold text-lg shadow-[0_0_20px_-5px_rgb(var(--color-primary))] transition-transform active:scale-95"
80-
>
81-
<Download size={24} />
82-
<span>INSTALL_WALLPAPER</span>
83-
</button>
84-
</div>
85-
</div>
86-
</div>
87-
)}
129+
<div className="absolute bottom-12 w-full px-8">
130+
<button
131+
disabled={downloading}
132+
onClick={(e) => {
133+
e.stopPropagation();
134+
handleDownload(selectedWallpaper.url, selectedWallpaper.name);
135+
}}
136+
className={`w-full flex items-center justify-center gap-3 px-6 py-4 rounded-xl font-bold text-lg shadow-[0_0_20px_-5px_rgb(var(--color-primary))] transition-all active:scale-95
137+
${downloading ? 'bg-primary/50 cursor-wait' : 'bg-primary hover:bg-primary/90 text-background'}
138+
`}
139+
>
140+
{downloading ? (
141+
<>
142+
<Loader2 size={24} className="animate-spin" />
143+
<span>{t.downloading}</span>
144+
</>
145+
) : (
146+
<>
147+
<Download size={24} />
148+
<span>{t.download_save}</span>
149+
</>
150+
)}
151+
</button>
152+
</div>
153+
</div>
154+
</div>
155+
)}
88156
</div>
89157
);
90158
};

0 commit comments

Comments
 (0)