Skip to content
This repository was archived by the owner on Jul 18, 2026. It is now read-only.

Commit f26979d

Browse files
authored
Merge pull request #155 from misaka10032w/develop
[Add] 增加公告展开功能、播放位置跳转功能、调整播放器布局样式、修复使用私有目录无法删除已下载文件的问题
2 parents 6f87796 + cd73e98 commit f26979d

24 files changed

Lines changed: 562 additions & 114 deletions

File tree

HanimeAnnouncementManagerWebUI/HanimeAnnouncementManager.html

Lines changed: 38 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -30,19 +30,24 @@ <h2>新增公告</h2>
3030
<input type="text" id="title" placeholder="标题" required>
3131
<textarea id="content" placeholder="内容" required></textarea>
3232
<input type="text" id="imageUrl" placeholder="图片URL (可选)">
33-
<input type="number" id="priority" placeholder="优先级 (1-3)" value="2">
33+
<input type="text" id="positiveText" placeholder="确定按钮文本">
34+
<input type="text" id="negativeText" placeholder="取消按钮文本">
35+
<input type="number" id="priority" placeholder="优先级 (0-5)" value="2">
3436
<button type="submit">添加公告</button>
3537
</form>
3638

3739
<h2>公告列表</h2>
3840
<table>
3941
<thead>
40-
<tr>
41-
<th>标题</th>
42-
<th>时间</th>
43-
<th>状态</th>
44-
<th>操作</th>
45-
</tr>
42+
<tr>
43+
<th>标题</th>
44+
<th>内容</th>
45+
<th>优先级</th>
46+
<th>时间</th>
47+
<th>状态</th>
48+
<th>图片URL</th>
49+
<th>操作</th>
50+
</tr>
4651
</thead>
4752
<tbody id="announcementList"></tbody>
4853
</table>
@@ -60,7 +65,7 @@ <h2>公告列表</h2>
6065
appId: "",
6166
measurementId: ""
6267
};
63-
68+
6469

6570
firebase.initializeApp(firebaseConfig);
6671
const db = firebase.database();
@@ -91,8 +96,11 @@ <h2>公告列表</h2>
9196
const tr = document.createElement('tr');
9297
tr.innerHTML = `
9398
<td>${data.title}</td>
99+
<td>${data.content}</td>
100+
<td>${data.priority}</td>
94101
<td>${new Date(data.timestamp * 1000).toLocaleString()}</td>
95102
<td>${data.isActive ? '启用' : '停用'}</td>
103+
<td><a href="${data.imageUrl}" target="_blank">查看图片</a></td>
96104
<td>
97105
<button class="toggle">${data.isActive ? '停用' : '启用'}</button>
98106
<button class="edit">编辑</button>
@@ -115,7 +123,9 @@ <h2>公告列表</h2>
115123
title: document.getElementById('title').value,
116124
content: document.getElementById('content').value,
117125
imageUrl: document.getElementById('imageUrl').value || '',
118-
priority: parseInt(document.getElementById('priority').value || 2),
126+
positiveText: document.getElementById('positiveText').value || '',
127+
negativeText: document.getElementById('negativeText').value || '',
128+
priority: parseInt(document.getElementById('priority').value || 1),
119129
timestamp: Math.floor(Date.now() / 1000),
120130
isActive: true
121131
}).then(() => {
@@ -126,26 +136,37 @@ <h2>公告列表</h2>
126136
});
127137
};
128138

139+
// 切换公告状态
129140
function toggleActive(key, active) {
130141
db.ref('announcements/' + key + '/isActive').set(active).then(loadAnnouncements);
131142
}
132143

144+
// 删除公告
133145
function deleteAnnouncement(key) {
134146
if (confirm('确定要删除该公告吗?')) {
135147
db.ref('announcements/' + key).remove().then(loadAnnouncements);
136148
}
137149
}
138150

151+
// 编辑公告
139152
function editAnnouncement(key, data) {
140153
const newTitle = prompt('修改标题:', data.title);
141-
if (newTitle !== null) {
142-
const newContent = prompt('修改内容:', data.content);
143-
if (newContent !== null) {
144-
db.ref('announcements/' + key).update({
145-
title: newTitle,
146-
content: newContent
147-
}).then(loadAnnouncements);
148-
}
154+
const newContent = prompt('修改内容:', data.content);
155+
const newImageUrl = prompt('修改图片URL:', data.imageUrl);
156+
const newPositiveText = prompt('修改确定按钮文本:', data.positiveText);
157+
const newNegativeText = prompt('修改取消按钮文本:', data.negativeText);
158+
const newPriority = prompt('修改优先级:', data.priority);
159+
160+
if (newTitle !== null && newContent !== null && newPriority !== null) {
161+
db.ref('announcements/' + key).update({
162+
title: newTitle,
163+
content: newContent,
164+
imageUrl: newImageUrl || '',
165+
positiveText: newPositiveText || '确定',
166+
negativeText: newNegativeText || '取消',
167+
priority: parseInt(newPriority),
168+
timestamp: Math.floor(Date.now() / 1000), // 更新时间戳
169+
}).then(loadAnnouncements);
149170
}
150171
}
151172
</script>

app/src/main/java/com/yenaly/han1meviewer/Preferences.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,8 @@ object Preferences {
203203
get() = preferenceSp.getString(HomeSettingsFragment.USE_DARK_MODE,"always_off") ?: "always_off"
204204
val useDynamicColor: Boolean
205205
get() = preferenceSp.getBoolean(HomeSettingsFragment.USE_DYNAMIC_COLOR,false)
206+
val allowResumePlayback: Boolean
207+
get() = preferenceSp.getBoolean(HomeSettingsFragment.ALLOW_RESUME_PLAYBACK,true)
206208
/**
207209
* 对应关系详见 [SpeedLimitInterceptor.SPEED_BYTES]
208210
*/

app/src/main/java/com/yenaly/han1meviewer/logic/DatabaseRepo.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,8 +157,14 @@ object DatabaseRepo {
157157
suspend fun update(history: WatchHistoryEntity) =
158158
watchHistoryDao.update(history)
159159

160+
suspend fun updateProgress(videoCode: String,progress: Long) =
161+
watchHistoryDao.updateProgress(videoCode, progress)
162+
160163
suspend fun insert(history: WatchHistoryEntity) =
161164
watchHistoryDao.insertOrUpdate(history)
165+
166+
suspend fun findBy(videoCode: String) =
167+
watchHistoryDao.findBy(videoCode)
162168
}
163169

164170
object HanimeDownload {

app/src/main/java/com/yenaly/han1meviewer/logic/dao/HistoryDatabase.kt

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import com.yenaly.yenaly_libs.utils.applicationContext
1818
*/
1919
@Database(
2020
entities = [SearchHistoryEntity::class, WatchHistoryEntity::class],
21-
version = 2, exportSchema = false
21+
version = 3, exportSchema = false
2222
)
2323
abstract class HistoryDatabase : RoomDatabase() {
2424

@@ -32,7 +32,7 @@ abstract class HistoryDatabase : RoomDatabase() {
3232
applicationContext,
3333
HistoryDatabase::class.java,
3434
"history.db"
35-
).addMigrations(Migration1To2).build()
35+
).addMigrations(Migration1To2, Migration2To3).build()
3636
}
3737
}
3838

@@ -61,6 +61,15 @@ abstract class HistoryDatabase : RoomDatabase() {
6161
)
6262
}
6363
}
64+
object Migration2To3 : Migration(2, 3) {
65+
override fun migrate(db: SupportSQLiteDatabase) {
66+
// 增加播放进度列,默认值为 0
67+
db.execSQL(
68+
"""ALTER TABLE WatchHistoryEntity
69+
ADD COLUMN progress INTEGER NOT NULL DEFAULT 0"""
70+
)
71+
}
72+
}
6473
}
6574

6675

app/src/main/java/com/yenaly/han1meviewer/logic/dao/WatchHistoryDao.kt

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,20 @@ abstract class WatchHistoryDao {
3030
@Query("SELECT * FROM WatchHistoryEntity WHERE (`videoCode` = :videoCode) LIMIT 1")
3131
abstract suspend fun findBy(videoCode: String): WatchHistoryEntity?
3232

33+
@Query("UPDATE WatchHistoryEntity SET progress = :progress WHERE videoCode = :videoCode")
34+
abstract suspend fun updateProgress(videoCode: String, progress: Long)
35+
3336
@Transaction
3437
open suspend fun insertOrUpdate(history: WatchHistoryEntity) {
3538
val dbEntity = findBy(history.videoCode)
3639
if (dbEntity != null) {
37-
delete(dbEntity)
40+
val merged = history.copy(
41+
id = dbEntity.id,
42+
progress = if (history.progress == 0L) dbEntity.progress else history.progress
43+
)
44+
update(merged)
45+
} else {
3846
insert(history)
39-
return
4047
}
41-
insert(history)
4248
}
4349
}

app/src/main/java/com/yenaly/han1meviewer/logic/entity/WatchHistoryEntity.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ data class WatchHistoryEntity(
1414
val title: String,
1515
val releaseDate: Long,
1616
val watchDate: Long,
17-
1817
val videoCode: String,
18+
val progress: Long = 0L,
1919
@PrimaryKey(autoGenerate = true)
2020
val id: Int = 0,
2121
) {
Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
package com.yenaly.han1meviewer.logic.model
22

3+
import android.graphics.Color
4+
import android.text.SpannableString
5+
import android.text.Spanned
6+
import android.text.style.ForegroundColorSpan
37
import androidx.annotation.Keep
48
import com.yenaly.han1meviewer.LOCAL_DATE_TIME_FORMAT
59
import kotlinx.datetime.TimeZone
@@ -9,18 +13,36 @@ import kotlin.time.ExperimentalTime
913

1014
@Keep
1115
data class Announcement(
12-
@JvmField val title: String = "",
13-
@JvmField val content: String = "",
16+
@JvmField val title: String,
17+
@JvmField val content: String,
18+
@JvmField val positiveText: String ? = null,
19+
@JvmField val negativeText: String ? = null,
1420
@JvmField val timestamp: Long = 0,
15-
@JvmField val priority: Int = 2,
16-
@JvmField val imageUrl: String = "",
21+
@JvmField val priority: Int = 1,
22+
@JvmField val imageUrl: String ? = null,
1723
@JvmField val isActive: Boolean = false
1824
) {
25+
//firebase初始化需要一个空的构造函数
26+
constructor() : this("", "", null, null, 0L, 1, null, false)
1927
@OptIn(ExperimentalTime::class)
2028
fun getFormattedDate(): String {
2129
return kotlin.time.Instant
2230
.fromEpochSeconds(timestamp)
2331
.toLocalDateTime(TimeZone.currentSystemDefault())
2432
.format(LOCAL_DATE_TIME_FORMAT)
2533
}
34+
fun getHighlightedContent(): Spanned {
35+
val regex = "(https?://[\\w-]+(\\.[\\w-]+)+([/?%&=]*)?)".toRegex()
36+
val spannableContent = SpannableString(content)
37+
val matches = regex.findAll(content)
38+
39+
for (match in matches) {
40+
spannableContent.setSpan(
41+
ForegroundColorSpan(Color.BLUE),
42+
match.range.first, match.range.last + 1,
43+
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
44+
)
45+
}
46+
return spannableContent
47+
}
2648
}

app/src/main/java/com/yenaly/han1meviewer/ui/adapter/HanimeDownloadedRvAdapter.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ import androidx.recyclerview.widget.DiffUtil
1414
import com.chad.library.adapter4.BaseDifferAdapter
1515
import com.chad.library.adapter4.viewholder.DataBindingHolder
1616
import com.yenaly.han1meviewer.FROM_DOWNLOAD
17-
import com.yenaly.han1meviewer.HFileManager
1817
import com.yenaly.han1meviewer.LOCAL_DATE_TIME_FORMAT
1918
import com.yenaly.han1meviewer.R
2019
import com.yenaly.han1meviewer.VIDEO_CODE

0 commit comments

Comments
 (0)