Feature: Manual leaderboard submission button on result screen with notification
This commit is contained in:
@@ -178,7 +178,66 @@ class Scoresheet {
|
|||||||
}
|
}
|
||||||
this.game.appendChild(this.tetsuoHana)
|
this.game.appendChild(this.tetsuoHana)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add leaderboard submit button if user is logged in
|
||||||
|
if (account.loggedIn && !this.multiplayer) {
|
||||||
|
this.leaderboardBtn = document.createElement("div")
|
||||||
|
this.leaderboardBtn.id = "leaderboard-submit-btn"
|
||||||
|
this.leaderboardBtn.innerHTML = "🏆 提交排行榜<br><small>Submit to Leaderboard</small>"
|
||||||
|
this.leaderboardBtn.style.cssText = `
|
||||||
|
position: fixed;
|
||||||
|
bottom: 20px;
|
||||||
|
right: 20px;
|
||||||
|
padding: 15px 25px;
|
||||||
|
background: linear-gradient(135deg, #ff6b9d, #c44db3);
|
||||||
|
color: white;
|
||||||
|
border-radius: 15px;
|
||||||
|
font-size: 18px;
|
||||||
|
font-family: ${strings.font || "sans-serif"};
|
||||||
|
text-align: center;
|
||||||
|
cursor: pointer;
|
||||||
|
z-index: 1000;
|
||||||
|
box-shadow: 0 4px 15px rgba(0,0,0,0.3);
|
||||||
|
border: 3px solid #fff;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
user-select: none;
|
||||||
|
`
|
||||||
|
this.leaderboardBtn.onmouseover = () => {
|
||||||
|
if (!this.leaderboardSubmitted) {
|
||||||
|
this.leaderboardBtn.style.transform = "scale(1.05)"
|
||||||
|
this.leaderboardBtn.style.boxShadow = "0 6px 20px rgba(0,0,0,0.4)"
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
this.leaderboardBtn.onmouseout = () => {
|
||||||
|
this.leaderboardBtn.style.transform = "scale(1)"
|
||||||
|
this.leaderboardBtn.style.boxShadow = "0 4px 15px rgba(0,0,0,0.3)"
|
||||||
|
}
|
||||||
|
this.leaderboardBtn.onclick = () => this.onLeaderboardBtnClick()
|
||||||
|
this.game.appendChild(this.leaderboardBtn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onLeaderboardBtnClick() {
|
||||||
|
if (this.leaderboardSubmitted) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!this.leaderboardData || !this.leaderboardData.songId) {
|
||||||
|
this.showLeaderboardNotification("no_song_id")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disable button and show submitting state
|
||||||
|
this.leaderboardBtn.innerHTML = "⏳ 提交中..."
|
||||||
|
this.leaderboardBtn.style.background = "linear-gradient(135deg, #888, #666)"
|
||||||
|
this.leaderboardBtn.style.cursor = "default"
|
||||||
|
|
||||||
|
this.submitToLeaderboard(
|
||||||
|
this.leaderboardData.songId,
|
||||||
|
this.leaderboardData.difficulty,
|
||||||
|
this.leaderboardData.scoreObj
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
redraw() {
|
redraw() {
|
||||||
if (!this.redrawRunning) {
|
if (!this.redrawRunning) {
|
||||||
@@ -933,6 +992,15 @@ class Scoresheet {
|
|||||||
if (clearReached) {
|
if (clearReached) {
|
||||||
crown = this.resultsObj.bad === 0 ? "gold" : "silver"
|
crown = this.resultsObj.bad === 0 ? "gold" : "silver"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Store data for manual leaderboard submission
|
||||||
|
this.leaderboardData = {
|
||||||
|
songId: songId,
|
||||||
|
difficulty: difficulty,
|
||||||
|
scoreObj: Object.assign({}, this.resultsObj)
|
||||||
|
}
|
||||||
|
this.leaderboardSubmitted = false
|
||||||
|
|
||||||
if (!oldScore || oldScore.points <= this.resultsObj.points) {
|
if (!oldScore || oldScore.points <= this.resultsObj.points) {
|
||||||
if (oldScore && (oldScore.crown === "gold" || oldScore.crown === "silver" && !crown)) {
|
if (oldScore && (oldScore.crown === "gold" || oldScore.crown === "silver" && !crown)) {
|
||||||
crown = oldScore.crown
|
crown = oldScore.crown
|
||||||
@@ -941,10 +1009,7 @@ class Scoresheet {
|
|||||||
delete this.resultsObj.title
|
delete this.resultsObj.title
|
||||||
delete this.resultsObj.difficulty
|
delete this.resultsObj.difficulty
|
||||||
delete this.resultsObj.gauge
|
delete this.resultsObj.gauge
|
||||||
scoreStorage.add(hash, difficulty, this.resultsObj, true, title).then(() => {
|
scoreStorage.add(hash, difficulty, this.resultsObj, true, title).catch(() => {
|
||||||
// Auto-submit to leaderboard if logged in and has song ID
|
|
||||||
this.submitToLeaderboard(songId, difficulty, this.resultsObj)
|
|
||||||
}).catch(() => {
|
|
||||||
this.showWarning = { name: "scoreSaveFailed" }
|
this.showWarning = { name: "scoreSaveFailed" }
|
||||||
})
|
})
|
||||||
} else if (oldScore && (crown === "gold" && oldScore.crown !== "gold" || crown && !oldScore.crown)) {
|
} else if (oldScore && (crown === "gold" && oldScore.crown !== "gold" || crown && !oldScore.crown)) {
|
||||||
@@ -957,13 +1022,13 @@ class Scoresheet {
|
|||||||
this.scoreSaved = true
|
this.scoreSaved = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
submitToLeaderboard(songId, difficulty, scoreObj) {
|
submitToLeaderboard(songId, difficulty, scoreObj) {
|
||||||
// Only submit if user is logged in and song has an ID
|
// Only submit if user is logged in and song has an ID
|
||||||
if (!account.loggedIn || !songId) {
|
if (!account.loggedIn || !songId) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var self = this
|
var self = this
|
||||||
loader.getCsrfToken().then(token => {
|
loader.getCsrfToken().then(token => {
|
||||||
var request = new XMLHttpRequest()
|
var request = new XMLHttpRequest()
|
||||||
@@ -976,11 +1041,39 @@ class Scoresheet {
|
|||||||
try {
|
try {
|
||||||
var response = JSON.parse(request.responseText)
|
var response = JSON.parse(request.responseText)
|
||||||
if (response.status === "ok") {
|
if (response.status === "ok") {
|
||||||
|
self.leaderboardSubmitted = true
|
||||||
self.showLeaderboardNotification(response.message)
|
self.showLeaderboardNotification(response.message)
|
||||||
|
// Update button to show success
|
||||||
|
if (self.leaderboardBtn) {
|
||||||
|
self.leaderboardBtn.innerHTML = "✅ 已提交<br><small>Submitted!</small>"
|
||||||
|
self.leaderboardBtn.style.background = "linear-gradient(135deg, #4CAF50, #45a049)"
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Show error
|
||||||
|
self.showLeaderboardNotification("error")
|
||||||
|
if (self.leaderboardBtn) {
|
||||||
|
self.leaderboardBtn.innerHTML = "❌ 失败<br><small>Failed</small>"
|
||||||
|
self.leaderboardBtn.style.background = "linear-gradient(135deg, #f44336, #d32f2f)"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("Failed to parse leaderboard response:", e)
|
console.error("Failed to parse leaderboard response:", e)
|
||||||
|
self.showLeaderboardNotification("error")
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
self.showLeaderboardNotification("error")
|
||||||
|
if (self.leaderboardBtn) {
|
||||||
|
self.leaderboardBtn.innerHTML = "❌ 失败<br><small>Failed</small>"
|
||||||
|
self.leaderboardBtn.style.background = "linear-gradient(135deg, #f44336, #d32f2f)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
request.onerror = function () {
|
||||||
|
self.showLeaderboardNotification("error")
|
||||||
|
if (self.leaderboardBtn) {
|
||||||
|
self.leaderboardBtn.innerHTML = "❌ 失败<br><small>Failed</small>"
|
||||||
|
self.leaderboardBtn.style.background = "linear-gradient(135deg, #f44336, #d32f2f)"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -991,9 +1084,15 @@ class Scoresheet {
|
|||||||
}))
|
}))
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
console.log("Leaderboard submission failed")
|
console.log("Leaderboard submission failed")
|
||||||
|
this.showLeaderboardNotification("error")
|
||||||
|
if (this.leaderboardBtn) {
|
||||||
|
this.leaderboardBtn.innerHTML = "❌ 失败<br><small>Failed</small>"
|
||||||
|
this.leaderboardBtn.style.background = "linear-gradient(135deg, #f44336, #d32f2f)"
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
showLeaderboardNotification(message) {
|
showLeaderboardNotification(message) {
|
||||||
var notification = document.createElement("div")
|
var notification = document.createElement("div")
|
||||||
notification.className = "leaderboard-notification"
|
notification.className = "leaderboard-notification"
|
||||||
@@ -1020,6 +1119,8 @@ class Scoresheet {
|
|||||||
case "score_updated": text = "🎉 排行榜成绩已更新!"; break
|
case "score_updated": text = "🎉 排行榜成绩已更新!"; break
|
||||||
case "score_not_higher": text = "📊 已有更高成绩"; break
|
case "score_not_higher": text = "📊 已有更高成绩"; break
|
||||||
case "score_too_low": text = "未进入排行榜前50"; break
|
case "score_too_low": text = "未进入排行榜前50"; break
|
||||||
|
case "error": text = "❌ 提交失败,请重试"; break
|
||||||
|
case "no_song_id": text = "❌ 无法提交:歌曲ID缺失"; break
|
||||||
default: text = "排行榜已更新"
|
default: text = "排行榜已更新"
|
||||||
}
|
}
|
||||||
notification.innerText = text
|
notification.innerText = text
|
||||||
@@ -1063,10 +1164,17 @@ class Scoresheet {
|
|||||||
if (!this.multiplayer) {
|
if (!this.multiplayer) {
|
||||||
delete this.tetsuoHana
|
delete this.tetsuoHana
|
||||||
}
|
}
|
||||||
|
// Clean up leaderboard button
|
||||||
|
if (this.leaderboardBtn && this.leaderboardBtn.parentNode) {
|
||||||
|
this.leaderboardBtn.parentNode.removeChild(this.leaderboardBtn)
|
||||||
|
}
|
||||||
|
delete this.leaderboardBtn
|
||||||
|
delete this.leaderboardData
|
||||||
delete this.ctx
|
delete this.ctx
|
||||||
delete this.canvas
|
delete this.canvas
|
||||||
delete this.fadeScreen
|
delete this.fadeScreen
|
||||||
delete this.results
|
delete this.results
|
||||||
delete this.rules
|
delete this.rules
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user