feat: android logo change and navbar hiding

This commit is contained in:
neoapps-dev 2026-08-09 00:31:22 +03:00
parent d890f9b94a
commit e221396911
20 changed files with 121 additions and 222 deletions

View file

@ -34,7 +34,7 @@ android {
defaultConfig {
manifestPlaceholders["usesCleartextTraffic"] = "false"
applicationId = "com.emerald.legacy"
minSdk = 24
minSdk = 26
targetSdk = 36
versionCode = tauriProperties.getProperty("tauri.android.versionCode", "1").toInt()
versionName = tauriProperties.getProperty("tauri.android.versionName", "1.0")

View file

@ -13,7 +13,7 @@ class MainActivity : TauriActivity() {
super.onCreate(savedInstanceState)
WindowCompat.getInsetsController(window, window.decorView).apply {
systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
hide(WindowInsetsCompat.Type.statusBars())
hide(WindowInsetsCompat.Type.statusBars() or WindowInsetsCompat.Type.navigationBars())
}
}

View file

@ -5,166 +5,6 @@
android:viewportWidth="108"
android:viewportHeight="108">
<path
android:fillColor="#3DDC84"
android:fillColor="#00591C"
android:pathData="M0,0h108v108h-108z" />
<path
android:fillColor="#00000000"
android:pathData="M9,0L9,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,0L19,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,0L29,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,0L39,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,0L49,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,0L59,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,0L69,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,0L79,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M89,0L89,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M99,0L99,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,9L108,9"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,19L108,19"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,29L108,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,39L108,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,49L108,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,59L108,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,69L108,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,79L108,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,89L108,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,99L108,99"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,29L89,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,39L89,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,49L89,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,59L89,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,69L89,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,79L89,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,19L29,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,19L39,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,19L49,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,19L59,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,19L69,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,19L79,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
</vector>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.9 KiB

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.8 KiB

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.8 KiB

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 9.1 KiB

View file

@ -67,7 +67,7 @@
"signingIdentity": null
},
"android": {
"minSdkVersion": 24,
"minSdkVersion": 26,
"versionCode": 1006000
}
}

View file

@ -93,21 +93,32 @@ const VersionsView = memo(function VersionsView() {
const [setUidTargetId, setSetUidTargetId] = useState("");
const [editingEdition, setEditingEdition] = useState<Edition | null>(null);
const [isImportWorldModalOpen, setIsImportWorldModalOpen] = useState(false);
const [importWorldTarget, setImportWorldTarget] = useState<{ id: string; name: string } | null>(null);
const [importWorldTarget, setImportWorldTarget] = useState<{
id: string;
name: string;
} | null>(null);
const [isPlaytimeModalOpen, setIsPlaytimeModalOpen] = useState(false);
const [playtimeTarget, setPlaytimeTarget] = useState<{ id: string; name: string } | null>(null);
const [playtimeTarget, setPlaytimeTarget] = useState<{
id: string;
name: string;
} | null>(null);
const [isCustomizeModalOpen, setIsCustomizeModalOpen] = useState(false);
const [customizeTarget, setCustomizeTarget] = useState<Edition | null>(null);
const [playtimeMap, setPlaytimeMap] = useState<Record<string, PlaytimeResponse>>({});
const [playtimeMap, setPlaytimeMap] = useState<
Record<string, PlaytimeResponse>
>({});
const [initialPath, setInitialPath] = useState<string>("");
const [hoveredBtn, setHoveredBtn] = useState<{
row: number;
btn: string;
} | null>(null);
const [openMenuId, setOpenMenuId] = useState<string | null>(null);
const [deleteConfirmEdition, setDeleteConfirmEdition] = useState<Edition | null>(null);
const [deleteConfirmEdition, setDeleteConfirmEdition] =
useState<Edition | null>(null);
const [isDlcModalOpen, setIsDlcModalOpen] = useState(false);
const [dlcTargetEdition, setDlcTargetEdition] = useState<Edition | null>(null);
const [dlcTargetEdition, setDlcTargetEdition] = useState<Edition | null>(
null,
);
const containerRef = useRef<HTMLDivElement>(null);
const listRef = useRef<HTMLDivElement>(null);
const ITEM_COUNT = editions.length + 3;
@ -218,13 +229,15 @@ const VersionsView = memo(function VersionsView() {
useEffect(() => {
const fetchPlaytimes = async () => {
const map: Record<string, PlaytimeResponse> = {};
await Promise.all(installedVersions.map(async (id) => {
try {
map[id] = await TauriService.getPlaytime(id);
} catch (e) {
console.error(e);
}
}));
await Promise.all(
installedVersions.map(async (id) => {
try {
map[id] = await TauriService.getPlaytime(id);
} catch (e) {
console.error(e);
}
}),
);
setPlaytimeMap(map);
};
fetchPlaytimes();
@ -270,9 +283,7 @@ const VersionsView = memo(function VersionsView() {
Versions
</h2>
<div
className="w-full min-w-[480px] p-6 mb-4 mc-options-bg"
>
<div className="w-full min-w-[480px] p-6 mb-4 mc-options-bg">
<div
ref={listRef}
className="w-full max-h-[45vh] overflow-y-auto py-2 custom-scrollbar"
@ -352,7 +363,10 @@ const VersionsView = memo(function VersionsView() {
onClick={(e) => {
e.stopPropagation();
playPressSound();
setPlaytimeTarget({ id: edition.instanceId, name: edition.name });
setPlaytimeTarget({
id: edition.instanceId,
name: edition.name,
});
setIsPlaytimeModalOpen(true);
}}
className="flex items-center gap-1.5 px-2 py-1 bg-black/60 border border-[#555] hover:border-[#FFFF55] group transition-colors flex-shrink-0"
@ -373,7 +387,11 @@ const VersionsView = memo(function VersionsView() {
<polyline points="12 6 12 12 16 14" />
</svg>
<span className="text-xs text-[#AAAAAA] group-hover:text-[#FFFF55] leading-none transition-colors">
{playtimeMap[edition.instanceId] ? formatPlaytime(playtimeMap[edition.instanceId].totalSeconds) : ""}
{playtimeMap[edition.instanceId]
? formatPlaytime(
playtimeMap[edition.instanceId].totalSeconds,
)
: ""}
</span>
</button>
)}
@ -521,9 +539,11 @@ const VersionsView = memo(function VersionsView() {
try {
const folder = await TauriService.pickFolder();
if (folder) {
const entries = await TauriService.listDirectory(folder);
const entries =
await TauriService.listDirectory(folder);
if (entries.length > 0) {
const dialog = document.createElement("div");
const dialog =
document.createElement("div");
dialog.className =
"fixed inset-0 bg-black/80 flex items-center justify-center z-50";
dialog.innerHTML = `
@ -536,14 +556,20 @@ const VersionsView = memo(function VersionsView() {
</div>
`;
document.body.appendChild(dialog);
const close = () => document.body.removeChild(dialog);
dialog.querySelector("#empty-dir-ok")?.addEventListener("click", close);
const close = () =>
document.body.removeChild(dialog);
dialog
.querySelector("#empty-dir-ok")
?.addEventListener("click", close);
dialog.addEventListener("click", (e) => {
if (e.target === dialog) close();
});
return;
}
await saveCustomPath(edition.instanceId, folder);
await saveCustomPath(
edition.instanceId,
folder,
);
toggleInstall(edition.instanceId);
}
} catch (err) {
@ -612,7 +638,9 @@ const VersionsView = memo(function VersionsView() {
onClick={(e) => {
e.stopPropagation();
playPressSound();
TauriService.openInstanceFolder(edition.instanceId);
TauriService.openInstanceFolder(
edition.instanceId,
);
setOpenMenuId(null);
}}
className="w-full text-left px-3 py-2 text-xs text-[#dddddd] flex items-center gap-2 mc-text-shadow"
@ -693,7 +721,9 @@ const VersionsView = memo(function VersionsView() {
onClick={(e) => {
e.stopPropagation();
playPressSound();
TauriService.backupInstance(edition.instanceId).catch((err) => {
TauriService.backupInstance(
edition.instanceId,
).catch((err) => {
if (err !== "CANCELED") console.error(err);
});
setOpenMenuId(null);
@ -882,33 +912,35 @@ const VersionsView = memo(function VersionsView() {
</svg>
</button>
<button
onClick={() => {
playPressSound();
handleImportFolder();
}}
onMouseEnter={() => setFocusIndex(editions.length + 1)}
onMouseLeave={() => setHoveredBtn(null)}
title="Import Custom TU"
className="w-8 h-8 flex items-center justify-center text-[#3a3a3a]"
style={{
backgroundImage:
(hoveredBtn?.row === editions.length &&
hoveredBtn?.btn === "folder_import") ||
focusIndex === editions.length + 1
? "url('/images/Button_Square_Highlighted.png')"
: "url('/images/Button_Square.png')",
backgroundSize: "100% 100%",
imageRendering: "pixelated",
}}
>
<img
src="/images/Folder_Icon.png"
alt="Import Custom TU"
className="w-5 h-5 object-contain"
style={{ imageRendering: "pixelated" }}
/>
</button>
{!isAndroid && (
<button
onClick={() => {
playPressSound();
handleImportFolder();
}}
onMouseEnter={() => setFocusIndex(editions.length + 1)}
onMouseLeave={() => setHoveredBtn(null)}
title="Import Custom TU"
className="w-8 h-8 flex items-center justify-center text-[#3a3a3a]"
style={{
backgroundImage:
(hoveredBtn?.row === editions.length &&
hoveredBtn?.btn === "folder_import") ||
focusIndex === editions.length + 1
? "url('/images/Button_Square_Highlighted.png')"
: "url('/images/Button_Square.png')",
backgroundSize: "100% 100%",
imageRendering: "pixelated",
}}
>
<img
src="/images/Folder_Icon.png"
alt="Import Custom TU"
className="w-5 h-5 object-contain"
style={{ imageRendering: "pixelated" }}
/>
</button>
)}
</div>
</div>
</div>
@ -945,7 +977,12 @@ const VersionsView = memo(function VersionsView() {
setEditingEdition(null);
setInitialPath("");
}}
onImport={(ed: { name: string; desc: string; url: string; path?: string }) => {
onImport={(ed: {
name: string;
desc: string;
url: string;
path?: string;
}) => {
if (editingEdition) {
onUpdateEdition(editingEdition.id, ed);
} else {
@ -971,7 +1008,10 @@ const VersionsView = memo(function VersionsView() {
<ImportWorldModal
isOpen={isImportWorldModalOpen}
onClose={() => { setIsImportWorldModalOpen(false); setImportWorldTarget(null); }}
onClose={() => {
setIsImportWorldModalOpen(false);
setImportWorldTarget(null);
}}
playPressSound={playPressSound}
playBackSound={playBackSound}
targetInstanceId={importWorldTarget?.id ?? ""}
@ -980,7 +1020,10 @@ const VersionsView = memo(function VersionsView() {
<PlaytimeModal
isOpen={isPlaytimeModalOpen}
onClose={() => { setIsPlaytimeModalOpen(false); setPlaytimeTarget(null); }}
onClose={() => {
setIsPlaytimeModalOpen(false);
setPlaytimeTarget(null);
}}
playBackSound={playBackSound}
instanceId={playtimeTarget?.id ?? ""}
instanceName={playtimeTarget?.name ?? ""}
@ -988,12 +1031,25 @@ const VersionsView = memo(function VersionsView() {
<CustomizeModal
isOpen={isCustomizeModalOpen}
onClose={() => { setIsCustomizeModalOpen(false); setCustomizeTarget(null); }}
onClose={() => {
setIsCustomizeModalOpen(false);
setCustomizeTarget(null);
}}
playPressSound={playPressSound}
playBackSound={playBackSound}
editionName={customizeTarget?.name ?? ""}
currentTitleImage={customizeTarget ? customizations[customizeTarget.instanceId]?.titleImage || customizeTarget.titleImage : undefined}
currentPanorama={customizeTarget ? customizations[customizeTarget.instanceId]?.panorama || customizeTarget.panorama : undefined}
currentTitleImage={
customizeTarget
? customizations[customizeTarget.instanceId]?.titleImage ||
customizeTarget.titleImage
: undefined
}
currentPanorama={
customizeTarget
? customizations[customizeTarget.instanceId]?.panorama ||
customizeTarget.panorama
: undefined
}
onSave={(updates) => {
if (customizeTarget) {
updateCustomization(customizeTarget.instanceId, updates);
@ -1003,7 +1059,10 @@ const VersionsView = memo(function VersionsView() {
<DownloadDlcModal
isOpen={isDlcModalOpen}
onClose={() => { setIsDlcModalOpen(false); setDlcTargetEdition(null); }}
onClose={() => {
setIsDlcModalOpen(false);
setDlcTargetEdition(null);
}}
playPressSound={playPressSound}
playBackSound={playBackSound}
editionName={dlcTargetEdition?.name ?? ""}