Compare commits
5 Commits
7b7ca4f405
...
ae28ad17e5
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ae28ad17e5 | ||
|
|
7994b66ea1 | ||
|
|
d19d0cc631 | ||
|
|
669e2457a9 | ||
|
|
acebb8fc3e |
|
|
@ -197,6 +197,11 @@
|
||||||
android:name="com.example.livestreaming.UserProfileActivity"
|
android:name="com.example.livestreaming.UserProfileActivity"
|
||||||
android:exported="false" />
|
android:exported="false" />
|
||||||
|
|
||||||
|
<activity
|
||||||
|
android:name="com.example.livestreaming.PublishCenterActivity"
|
||||||
|
android:exported="false"
|
||||||
|
android:screenOrientation="portrait" />
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name="com.example.livestreaming.WishTreeActivity"
|
android:name="com.example.livestreaming.WishTreeActivity"
|
||||||
android:exported="false" />
|
android:exported="false" />
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
// 缘池 - 赛博梦幻版
|
// 缘池 - 可折叠底部面板版
|
||||||
|
// 保留所有原有功能
|
||||||
|
|
||||||
const AndroidBridge = {
|
const AndroidBridge = {
|
||||||
isAndroid: () => typeof Android !== 'undefined',
|
isAndroid: () => typeof Android !== 'undefined',
|
||||||
|
|
@ -19,9 +20,9 @@ const AndroidBridge = {
|
||||||
|
|
||||||
getMatchableCount: function() {
|
getMatchableCount: function() {
|
||||||
if (this.isAndroid()) {
|
if (this.isAndroid()) {
|
||||||
try { return Android.getMatchableCount(); } catch (e) { return '--'; }
|
try { return Android.getMatchableCount(); } catch (e) { return '20'; }
|
||||||
}
|
}
|
||||||
return '--';
|
return '20';
|
||||||
},
|
},
|
||||||
|
|
||||||
getCategories: function() {
|
getCategories: function() {
|
||||||
|
|
@ -31,41 +32,73 @@ const AndroidBridge = {
|
||||||
return [];
|
return [];
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// 点击用户头像 - 跳转到用户详情页
|
||||||
onUserClick: function(userId, userName) {
|
onUserClick: function(userId, userName) {
|
||||||
if (this.isAndroid()) Android.onUserClick(userId, userName);
|
if (this.isAndroid()) {
|
||||||
else console.log('点击用户:', userId, userName);
|
Android.onUserClick(userId, userName);
|
||||||
|
} else {
|
||||||
|
console.log('点击用户:', userId, userName);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// 点击板块 - 跳转到板块详情页
|
||||||
onCategoryClick: function(categoryId, categoryName, jumpPage) {
|
onCategoryClick: function(categoryId, categoryName, jumpPage) {
|
||||||
if (this.isAndroid()) Android.onCategoryClick(categoryId, categoryName, jumpPage);
|
if (this.isAndroid()) {
|
||||||
else console.log('点击板块:', categoryId, categoryName);
|
Android.onCategoryClick(parseInt(categoryId), categoryName, jumpPage || '');
|
||||||
|
} else {
|
||||||
|
console.log('点击板块:', categoryId, categoryName, jumpPage);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// 刷新数据
|
||||||
onRefresh: function() {
|
onRefresh: function() {
|
||||||
if (this.isAndroid()) Android.onRefresh();
|
if (this.isAndroid()) {
|
||||||
else console.log('刷新');
|
Android.onRefresh();
|
||||||
|
} else {
|
||||||
|
console.log('刷新');
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// 语音匹配
|
||||||
onVoiceMatch: function() {
|
onVoiceMatch: function() {
|
||||||
if (this.isAndroid()) Android.onVoiceMatch();
|
if (this.isAndroid()) {
|
||||||
else alert('语音匹配功能待接入~');
|
Android.onVoiceMatch();
|
||||||
|
} else {
|
||||||
|
alert('语音匹配功能待接入~');
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// 心动信号
|
||||||
onHeartSignal: function() {
|
onHeartSignal: function() {
|
||||||
if (this.isAndroid()) Android.onHeartSignal();
|
if (this.isAndroid()) {
|
||||||
else alert('心动信号功能待接入~');
|
Android.onHeartSignal();
|
||||||
|
} else {
|
||||||
|
alert('心动信号功能待接入~');
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
showToast: function(msg) {
|
showToast: function(msg) {
|
||||||
if (this.isAndroid()) Android.showToast(msg);
|
if (this.isAndroid()) {
|
||||||
else console.log('Toast:', msg);
|
Android.showToast(msg);
|
||||||
|
} else {
|
||||||
|
console.log('Toast:', msg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 缓存板块数据
|
||||||
|
let cachedCategories = [];
|
||||||
|
|
||||||
|
// 底部面板状态
|
||||||
|
let sheetExpanded = false;
|
||||||
|
let startY = 0;
|
||||||
|
let isDragging = false;
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', initPage);
|
document.addEventListener('DOMContentLoaded', initPage);
|
||||||
|
|
||||||
function initPage() {
|
function initPage() {
|
||||||
setupEventListeners();
|
setupEventListeners();
|
||||||
|
setupBottomSheet();
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
loadUserInfo();
|
loadUserInfo();
|
||||||
loadMatchableCount();
|
loadMatchableCount();
|
||||||
|
|
@ -75,58 +108,174 @@ function initPage() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function setupEventListeners() {
|
function setupEventListeners() {
|
||||||
// 刷新按钮
|
// 刷新按钮(中心按钮)- 调用原生刷新
|
||||||
document.getElementById('refreshBtn').addEventListener('click', function() {
|
const refreshBtn = document.getElementById('refreshBtn');
|
||||||
this.querySelector('.core-icon').style.animation = 'none';
|
if (refreshBtn) {
|
||||||
this.offsetHeight;
|
refreshBtn.addEventListener('click', function() {
|
||||||
this.querySelector('.core-icon').style.animation = 'spin 0.5s ease';
|
AndroidBridge.onRefresh();
|
||||||
AndroidBridge.onRefresh();
|
loadMatchableCount();
|
||||||
loadMatchableCount();
|
loadNearbyUsers();
|
||||||
loadNearbyUsers();
|
});
|
||||||
});
|
}
|
||||||
|
|
||||||
// 语音匹配
|
// 语音匹配 - 调用原生功能
|
||||||
document.getElementById('voiceMatchBtn').addEventListener('click', () => AndroidBridge.onVoiceMatch());
|
const voiceBtn = document.getElementById('voiceMatchBtn');
|
||||||
|
if (voiceBtn) {
|
||||||
|
voiceBtn.addEventListener('click', () => AndroidBridge.onVoiceMatch());
|
||||||
|
}
|
||||||
|
|
||||||
// 心动信号
|
// 心动信号 - 调用原生功能
|
||||||
document.getElementById('heartSignalBtn').addEventListener('click', () => AndroidBridge.onHeartSignal());
|
const heartBtn = document.getElementById('heartSignalBtn');
|
||||||
|
if (heartBtn) {
|
||||||
|
heartBtn.addEventListener('click', () => AndroidBridge.onHeartSignal());
|
||||||
|
}
|
||||||
|
|
||||||
// 用户头像点击
|
// 用户头像点击 - 跳转到用户详情页
|
||||||
document.querySelectorAll('.orbit-user').forEach(user => {
|
document.querySelectorAll('.orbit-user').forEach(user => {
|
||||||
user.addEventListener('click', function() {
|
user.addEventListener('click', function() {
|
||||||
const userId = this.dataset.userId || '';
|
const userId = this.dataset.userId || '';
|
||||||
const userName = this.querySelector('.user-name').textContent || '用户';
|
const userName = this.querySelector('.user-name').textContent || '用户';
|
||||||
if (userId) AndroidBridge.onUserClick(userId, userName);
|
if (userId) {
|
||||||
|
AndroidBridge.onUserClick(userId, userName);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// 功能卡片点击
|
// 底部面板卡片点击
|
||||||
document.querySelectorAll('.feature-card').forEach(card => {
|
setupCardListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
function setupCardListeners() {
|
||||||
|
// 快速匹配玩伴
|
||||||
|
document.querySelectorAll('.match-card').forEach(card => {
|
||||||
card.addEventListener('click', function() {
|
card.addEventListener('click', function() {
|
||||||
const id = parseInt(this.dataset.id) || 0;
|
const categoryId = this.dataset.categoryId || '0';
|
||||||
const name = this.querySelector('.card-title').textContent || '';
|
const categoryName = this.dataset.categoryName || '';
|
||||||
const jumpPage = this.dataset.jumpPage || '';
|
const jumpPage = this.dataset.jumpPage || '';
|
||||||
AndroidBridge.onCategoryClick(id, name, jumpPage);
|
AndroidBridge.onCategoryClick(categoryId, categoryName, jumpPage);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// 派对卡片
|
||||||
|
document.querySelectorAll('.party-card').forEach(card => {
|
||||||
|
card.addEventListener('click', function() {
|
||||||
|
const categoryId = this.dataset.categoryId || '0';
|
||||||
|
const categoryName = this.dataset.categoryName || '';
|
||||||
|
const jumpPage = this.dataset.jumpPage || '';
|
||||||
|
AndroidBridge.onCategoryClick(categoryId, categoryName, jumpPage);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// 小游戏
|
||||||
|
document.querySelectorAll('.game-item').forEach(item => {
|
||||||
|
item.addEventListener('click', function() {
|
||||||
|
const categoryId = this.dataset.categoryId || '0';
|
||||||
|
const categoryName = this.dataset.categoryName || '';
|
||||||
|
const jumpPage = this.dataset.jumpPage || '';
|
||||||
|
AndroidBridge.onCategoryClick(categoryId, categoryName, jumpPage);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// 一起玩
|
||||||
|
document.querySelectorAll('.together-card').forEach(card => {
|
||||||
|
card.addEventListener('click', function() {
|
||||||
|
const categoryId = this.dataset.categoryId || '0';
|
||||||
|
const categoryName = this.dataset.categoryName || '';
|
||||||
|
const jumpPage = this.dataset.jumpPage || '';
|
||||||
|
AndroidBridge.onCategoryClick(categoryId, categoryName, jumpPage);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// 添加旋转动画
|
// ========== 底部面板交互 ==========
|
||||||
const style = document.createElement('style');
|
function setupBottomSheet() {
|
||||||
style.textContent = '@keyframes spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }';
|
const sheet = document.getElementById('bottomSheet');
|
||||||
document.head.appendChild(style);
|
const handle = document.getElementById('sheetHandle');
|
||||||
|
const handleText = document.querySelector('.handle-text');
|
||||||
|
|
||||||
|
if (!sheet || !handle) return;
|
||||||
|
|
||||||
|
// 点击手柄或"上滑查看更多"切换展开/收起
|
||||||
|
handle.addEventListener('click', toggleSheet);
|
||||||
|
if (handleText) {
|
||||||
|
handleText.addEventListener('click', function(e) {
|
||||||
|
e.stopPropagation();
|
||||||
|
toggleSheet();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 点击"上滑查看更多"按钮
|
||||||
|
const expandBtn = document.getElementById('expandBtn');
|
||||||
|
if (expandBtn) {
|
||||||
|
expandBtn.addEventListener('click', function(e) {
|
||||||
|
e.stopPropagation();
|
||||||
|
expandSheet();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 触摸拖动
|
||||||
|
sheet.addEventListener('touchstart', onTouchStart, { passive: true });
|
||||||
|
sheet.addEventListener('touchmove', onTouchMove, { passive: false });
|
||||||
|
sheet.addEventListener('touchend', onTouchEnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleSheet() {
|
||||||
|
const sheet = document.getElementById('bottomSheet');
|
||||||
|
sheetExpanded = !sheetExpanded;
|
||||||
|
sheet.classList.toggle('expanded', sheetExpanded);
|
||||||
|
}
|
||||||
|
|
||||||
|
function expandSheet() {
|
||||||
|
const sheet = document.getElementById('bottomSheet');
|
||||||
|
sheetExpanded = true;
|
||||||
|
sheet.classList.add('expanded');
|
||||||
|
}
|
||||||
|
|
||||||
|
function collapseSheet() {
|
||||||
|
const sheet = document.getElementById('bottomSheet');
|
||||||
|
sheetExpanded = false;
|
||||||
|
sheet.classList.remove('expanded');
|
||||||
|
}
|
||||||
|
|
||||||
|
function onTouchStart(e) {
|
||||||
|
startY = e.touches[0].clientY;
|
||||||
|
isDragging = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function onTouchMove(e) {
|
||||||
|
if (!isDragging) return;
|
||||||
|
|
||||||
|
const currentY = e.touches[0].clientY;
|
||||||
|
const deltaY = startY - currentY;
|
||||||
|
|
||||||
|
// 上滑超过40px展开
|
||||||
|
if (deltaY > 40 && !sheetExpanded) {
|
||||||
|
expandSheet();
|
||||||
|
isDragging = false;
|
||||||
|
}
|
||||||
|
// 下滑超过40px收起
|
||||||
|
else if (deltaY < -40 && sheetExpanded) {
|
||||||
|
collapseSheet();
|
||||||
|
isDragging = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onTouchEnd() {
|
||||||
|
isDragging = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========== 数据加载 ==========
|
||||||
function loadUserInfo() {
|
function loadUserInfo() {
|
||||||
const info = AndroidBridge.getUserInfo();
|
const info = AndroidBridge.getUserInfo();
|
||||||
if (info) {
|
if (info && info.name) {
|
||||||
if (info.name) document.getElementById('userName').textContent = info.name;
|
console.log('用户信息:', info.name, info.info);
|
||||||
if (info.info) document.getElementById('userInfo').textContent = info.info;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadMatchableCount() {
|
function loadMatchableCount() {
|
||||||
const count = AndroidBridge.getMatchableCount();
|
const count = AndroidBridge.getMatchableCount();
|
||||||
document.getElementById('matchCount').textContent = count;
|
const el = document.getElementById('matchCount');
|
||||||
|
if (el) el.textContent = '剩余匹配' + count + '人';
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadNearbyUsers() {
|
function loadNearbyUsers() {
|
||||||
|
|
@ -137,12 +286,12 @@ function loadNearbyUsers() {
|
||||||
function renderOrbitUsers(users) {
|
function renderOrbitUsers(users) {
|
||||||
const userEls = document.querySelectorAll('.orbit-user');
|
const userEls = document.querySelectorAll('.orbit-user');
|
||||||
const defaultUsers = [
|
const defaultUsers = [
|
||||||
{ id: '1', name: '小树', location: '杭州' },
|
{ id: '1', name: '对你何止...', location: '美国 · 在线' },
|
||||||
{ id: '2', name: 'Lina', location: '深圳' },
|
{ id: '2', name: 'cat', location: '保密 · 在线' },
|
||||||
{ id: '3', name: '小七', location: '武汉' },
|
{ id: '3', name: '雾落溪漫', location: '桂林 · 在线' },
|
||||||
{ id: '4', name: '小北', location: '西安' },
|
{ id: '4', name: '313', location: '南宁 · 在线' },
|
||||||
{ id: '5', name: '暖暖', location: '成都' },
|
{ id: '5', name: 'ZwaC', location: '南宁 · 在线' },
|
||||||
{ id: '6', name: '阿宁', location: '南宁' }
|
{ id: '6', name: '小惠^', location: '崇左 · 在线' }
|
||||||
];
|
];
|
||||||
|
|
||||||
const data = (users && users.length > 0) ? users : defaultUsers;
|
const data = (users && users.length > 0) ? users : defaultUsers;
|
||||||
|
|
@ -150,15 +299,21 @@ function renderOrbitUsers(users) {
|
||||||
userEls.forEach((el, index) => {
|
userEls.forEach((el, index) => {
|
||||||
const user = data[index] || {};
|
const user = data[index] || {};
|
||||||
el.dataset.userId = user.id || '';
|
el.dataset.userId = user.id || '';
|
||||||
el.querySelector('.user-name').textContent = user.name || '用户';
|
|
||||||
el.querySelector('.user-location').textContent = user.location || '';
|
|
||||||
|
|
||||||
|
const nameEl = el.querySelector('.user-name');
|
||||||
|
const locationEl = el.querySelector('.user-location');
|
||||||
const img = el.querySelector('.avatar-img');
|
const img = el.querySelector('.avatar-img');
|
||||||
if (user.avatar) {
|
|
||||||
img.src = user.avatar;
|
if (nameEl) nameEl.textContent = user.name || '用户';
|
||||||
img.onerror = () => { img.src = ''; };
|
if (locationEl) locationEl.textContent = user.location || '';
|
||||||
} else {
|
|
||||||
img.src = '';
|
if (img) {
|
||||||
|
if (user.avatar) {
|
||||||
|
img.src = user.avatar;
|
||||||
|
img.onerror = () => { img.src = ''; };
|
||||||
|
} else {
|
||||||
|
img.src = '';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -166,40 +321,95 @@ function renderOrbitUsers(users) {
|
||||||
function loadCategories() {
|
function loadCategories() {
|
||||||
const categories = AndroidBridge.getCategories();
|
const categories = AndroidBridge.getCategories();
|
||||||
if (categories && categories.length > 0) {
|
if (categories && categories.length > 0) {
|
||||||
|
cachedCategories = categories;
|
||||||
renderCategories(categories);
|
renderCategories(categories);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 渲染板块到底部面板
|
||||||
function renderCategories(categories) {
|
function renderCategories(categories) {
|
||||||
const grid = document.getElementById('categoryGrid');
|
// 快速匹配玩伴区域 - 前3个板块
|
||||||
const defaultIcons = ['💕', '🎮', '🎤', '🎨', '🔫', '🎲'];
|
const matchCards = document.querySelectorAll('.match-card');
|
||||||
const defaultGlows = ['pink', 'cyan', 'purple', 'pink', 'cyan', 'purple'];
|
matchCards.forEach((card, index) => {
|
||||||
|
|
||||||
const cards = grid.querySelectorAll('.feature-card');
|
|
||||||
cards.forEach((card, index) => {
|
|
||||||
const cat = categories[index];
|
const cat = categories[index];
|
||||||
if (cat) {
|
if (cat) {
|
||||||
card.dataset.id = cat.id || index + 1;
|
card.dataset.categoryId = cat.id;
|
||||||
|
card.dataset.categoryName = cat.name || '';
|
||||||
card.dataset.jumpPage = cat.jumpPage || '';
|
card.dataset.jumpPage = cat.jumpPage || '';
|
||||||
card.querySelector('.card-title').textContent = cat.name || '未知';
|
|
||||||
|
const titleEl = card.querySelector('.match-title');
|
||||||
|
if (titleEl && cat.name) titleEl.textContent = cat.name;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 派对区域
|
||||||
|
const partyCards = document.querySelectorAll('.party-card');
|
||||||
|
partyCards.forEach((card, index) => {
|
||||||
|
const cat = categories[3 + index];
|
||||||
|
if (cat) {
|
||||||
|
card.dataset.categoryId = cat.id;
|
||||||
|
card.dataset.categoryName = cat.name || '';
|
||||||
|
card.dataset.jumpPage = cat.jumpPage || '';
|
||||||
|
|
||||||
|
const titleEl = card.querySelector('.party-title');
|
||||||
|
if (titleEl && cat.name) titleEl.textContent = cat.name;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 小游戏区域
|
||||||
|
const gameItems = document.querySelectorAll('.game-item');
|
||||||
|
gameItems.forEach((item, index) => {
|
||||||
|
const cat = categories[8 + index];
|
||||||
|
if (cat) {
|
||||||
|
item.dataset.categoryId = cat.id;
|
||||||
|
item.dataset.categoryName = cat.name || '';
|
||||||
|
item.dataset.jumpPage = cat.jumpPage || '';
|
||||||
|
|
||||||
|
const nameEl = item.querySelector('.game-name');
|
||||||
|
if (nameEl && cat.name) nameEl.textContent = cat.name;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 一起玩区域
|
||||||
|
const togetherCards = document.querySelectorAll('.together-card');
|
||||||
|
togetherCards.forEach((card, index) => {
|
||||||
|
const cat = categories[12 + index];
|
||||||
|
if (cat) {
|
||||||
|
card.dataset.categoryId = cat.id;
|
||||||
|
card.dataset.categoryName = cat.name || '';
|
||||||
|
card.dataset.jumpPage = cat.jumpPage || '';
|
||||||
|
|
||||||
|
const titleEl = card.querySelector('.together-title');
|
||||||
|
if (titleEl && cat.name) titleEl.textContent = cat.name;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Android回调
|
// ========== Android回调函数 ==========
|
||||||
function updateNearbyUsers(json) {
|
function updateNearbyUsers(json) {
|
||||||
try { renderOrbitUsers(JSON.parse(json)); } catch (e) {}
|
try {
|
||||||
|
const users = JSON.parse(json);
|
||||||
|
renderOrbitUsers(users);
|
||||||
|
} catch (e) {
|
||||||
|
console.error('解析用户数据失败:', e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateMatchableCount(count) {
|
function updateMatchableCount(count) {
|
||||||
document.getElementById('matchCount').textContent = count;
|
const el = document.getElementById('matchCount');
|
||||||
|
if (el) el.textContent = '剩余匹配' + count + '人';
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateCategories(json) {
|
function updateCategories(json) {
|
||||||
try { renderCategories(JSON.parse(json)); } catch (e) {}
|
try {
|
||||||
|
const categories = JSON.parse(json);
|
||||||
|
cachedCategories = categories;
|
||||||
|
renderCategories(categories);
|
||||||
|
} catch (e) {
|
||||||
|
console.error('解析板块数据失败:', e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateUserInfo(name, info) {
|
function updateUserInfo(name, info) {
|
||||||
if (name) document.getElementById('userName').textContent = name;
|
console.log('用户信息更新:', name, info);
|
||||||
if (info) document.getElementById('userInfo').textContent = info;
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -76,37 +76,37 @@
|
||||||
|
|
||||||
<!-- 心愿信笺卡片 -->
|
<!-- 心愿信笺卡片 -->
|
||||||
<div class="wish-notes" id="wishCards">
|
<div class="wish-notes" id="wishCards">
|
||||||
<div class="wish-note glass floating" data-index="0" style="--x: 12%; --y: 15%; --delay: 0s;">
|
<div class="wish-note glass floating" data-index="0" style="--x: 2%; --y: 55%; --delay: 0s;">
|
||||||
<div class="note-pin"></div>
|
<div class="note-pin"></div>
|
||||||
<div class="note-content"></div>
|
<div class="note-content"></div>
|
||||||
<div class="note-footer"><span class="heart">♥</span><span class="count">0</span></div>
|
<div class="note-footer"><span class="heart">♥</span><span class="count">0</span></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="wish-note glass floating" data-index="1" style="--x: 72%; --y: 12%; --delay: 0.4s;">
|
<div class="wish-note glass floating" data-index="1" style="--x: 15%; --y: 42%; --delay: 0.4s;">
|
||||||
<div class="note-pin"></div>
|
<div class="note-pin"></div>
|
||||||
<div class="note-content"></div>
|
<div class="note-content"></div>
|
||||||
<div class="note-footer"><span class="heart">♥</span><span class="count">0</span></div>
|
<div class="note-footer"><span class="heart">♥</span><span class="count">0</span></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="wish-note glass floating" data-index="2" style="--x: 5%; --y: 40%; --delay: 0.8s;">
|
<div class="wish-note glass floating" data-index="2" style="--x: 28%; --y: 52%; --delay: 0.8s;">
|
||||||
<div class="note-pin"></div>
|
<div class="note-pin"></div>
|
||||||
<div class="note-content"></div>
|
<div class="note-content"></div>
|
||||||
<div class="note-footer"><span class="heart">♥</span><span class="count">0</span></div>
|
<div class="note-footer"><span class="heart">♥</span><span class="count">0</span></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="wish-note glass floating" data-index="3" style="--x: 78%; --y: 38%; --delay: 1.2s;">
|
<div class="wish-note glass floating" data-index="3" style="--x: 55%; --y: 48%; --delay: 1.2s;">
|
||||||
<div class="note-pin"></div>
|
<div class="note-pin"></div>
|
||||||
<div class="note-content"></div>
|
<div class="note-content"></div>
|
||||||
<div class="note-footer"><span class="heart">♥</span><span class="count">0</span></div>
|
<div class="note-footer"><span class="heart">♥</span><span class="count">0</span></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="wish-note glass floating" data-index="4" style="--x: 18%; --y: 62%; --delay: 0.2s;">
|
<div class="wish-note glass floating" data-index="4" style="--x: 70%; --y: 55%; --delay: 0.2s;">
|
||||||
<div class="note-pin"></div>
|
<div class="note-pin"></div>
|
||||||
<div class="note-content"></div>
|
<div class="note-content"></div>
|
||||||
<div class="note-footer"><span class="heart">♥</span><span class="count">0</span></div>
|
<div class="note-footer"><span class="heart">♥</span><span class="count">0</span></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="wish-note glass floating" data-index="5" style="--x: 68%; --y: 60%; --delay: 0.6s;">
|
<div class="wish-note glass floating" data-index="5" style="--x: 82%; --y: 45%; --delay: 0.6s;">
|
||||||
<div class="note-pin"></div>
|
<div class="note-pin"></div>
|
||||||
<div class="note-content"></div>
|
<div class="note-content"></div>
|
||||||
<div class="note-footer"><span class="heart">♥</span><span class="count">0</span></div>
|
<div class="note-footer"><span class="heart">♥</span><span class="count">0</span></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="wish-note glass floating" data-index="6" style="--x: 42%; --y: 8%; --delay: 1s;">
|
<div class="wish-note glass floating" data-index="6" style="--x: 5%; --y: 70%; --delay: 1s;">
|
||||||
<div class="note-pin"></div>
|
<div class="note-pin"></div>
|
||||||
<div class="note-content"></div>
|
<div class="note-content"></div>
|
||||||
<div class="note-footer"><span class="heart">♥</span><span class="count">0</span></div>
|
<div class="note-footer"><span class="heart">♥</span><span class="count">0</span></div>
|
||||||
|
|
|
||||||
|
|
@ -12,41 +12,30 @@
|
||||||
<div class="bg-layer">
|
<div class="bg-layer">
|
||||||
<div class="gradient-orb orb-1"></div>
|
<div class="gradient-orb orb-1"></div>
|
||||||
<div class="gradient-orb orb-2"></div>
|
<div class="gradient-orb orb-2"></div>
|
||||||
<div class="grid-lines"></div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="pond-inner">
|
<div class="pond-inner">
|
||||||
<!-- 顶部栏 -->
|
<!-- 顶部栏 -->
|
||||||
<header class="top-bar">
|
<header class="top-bar">
|
||||||
<div class="logo-area">
|
<div class="top-left">
|
||||||
<span class="logo-glow">◈</span>
|
<span class="page-title">附近的人</span>
|
||||||
<span class="logo-text">FishPond</span>
|
</div>
|
||||||
|
<div class="top-right">
|
||||||
|
<span class="filter-btn">▼ 筛选</span>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<!-- 信息栏 -->
|
|
||||||
<section class="info-bar glass">
|
|
||||||
<div class="info-left">
|
|
||||||
<span class="info-label">剩余匹配</span>
|
|
||||||
<span class="info-value neon-text" id="matchCount">--</span>
|
|
||||||
<span class="info-unit">人</span>
|
|
||||||
</div>
|
|
||||||
<div class="info-right">
|
|
||||||
<span class="info-desc" id="userInfo">真诚 | 南宁 | 在线</span>
|
|
||||||
<span class="info-name neon-text" id="userName">加载中...</span>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<!-- 匹配圆环区域 -->
|
<!-- 匹配圆环区域 -->
|
||||||
<section class="match-area">
|
<section class="match-area">
|
||||||
<!-- 中心脉冲圆环 -->
|
<!-- 中心按钮 - 粉色圆形 -->
|
||||||
<div class="center-ring">
|
<div class="center-ring">
|
||||||
<div class="ring-pulse"></div>
|
<div class="ring-pulse"></div>
|
||||||
<div class="ring-pulse delay-1"></div>
|
<div class="ring-pulse delay-1"></div>
|
||||||
<div class="ring-pulse delay-2"></div>
|
<div class="ring-pulse delay-2"></div>
|
||||||
<div class="ring-core" id="refreshBtn">
|
<div class="ring-core" id="refreshBtn">
|
||||||
<div class="core-inner">
|
<div class="core-inner">
|
||||||
<span class="core-icon">⟳</span>
|
<span class="core-text">立即速配</span>
|
||||||
|
<span class="core-sub" id="matchCount">剩余匹配20人</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -54,104 +43,218 @@
|
||||||
<!-- 轨道环 -->
|
<!-- 轨道环 -->
|
||||||
<div class="orbit-ring"></div>
|
<div class="orbit-ring"></div>
|
||||||
|
|
||||||
<!-- 用户头像 - 摩天轮布局 -->
|
<!-- 用户头像 - 固定位置 -->
|
||||||
<div class="orbit-users" id="orbitGroup">
|
<div class="orbit-users" id="orbitGroup">
|
||||||
<div class="orbit-user" data-pos="1">
|
<div class="orbit-user" data-pos="1">
|
||||||
<div class="user-avatar glass">
|
<div class="user-avatar">
|
||||||
<img src="" alt="" class="avatar-img">
|
<img src="" alt="" class="avatar-img">
|
||||||
<div class="avatar-glow"></div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="user-name"></div>
|
<div class="user-name">对你何止...</div>
|
||||||
<div class="user-location"></div>
|
<div class="user-location">美国 · 在线</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="orbit-user" data-pos="2">
|
<div class="orbit-user" data-pos="2">
|
||||||
<div class="user-avatar glass">
|
<div class="user-avatar">
|
||||||
<img src="" alt="" class="avatar-img">
|
<img src="" alt="" class="avatar-img">
|
||||||
<div class="avatar-glow"></div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="user-name"></div>
|
<div class="user-name">cat</div>
|
||||||
<div class="user-location"></div>
|
<div class="user-location">保密 · 在线</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="orbit-user" data-pos="3">
|
<div class="orbit-user" data-pos="3">
|
||||||
<div class="user-avatar glass">
|
<div class="user-avatar">
|
||||||
<img src="" alt="" class="avatar-img">
|
<img src="" alt="" class="avatar-img">
|
||||||
<div class="avatar-glow"></div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="user-name"></div>
|
<div class="user-name">雾落溪漫</div>
|
||||||
<div class="user-location"></div>
|
<div class="user-location">桂林 · 在线</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="orbit-user" data-pos="4">
|
<div class="orbit-user" data-pos="4">
|
||||||
<div class="user-avatar glass">
|
<div class="user-avatar">
|
||||||
<img src="" alt="" class="avatar-img">
|
<img src="" alt="" class="avatar-img">
|
||||||
<div class="avatar-glow"></div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="user-name"></div>
|
<div class="user-name">313</div>
|
||||||
<div class="user-location"></div>
|
<div class="user-location">南宁 · 在线</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="orbit-user" data-pos="5">
|
<div class="orbit-user" data-pos="5">
|
||||||
<div class="user-avatar glass">
|
<div class="user-avatar">
|
||||||
<img src="" alt="" class="avatar-img">
|
<img src="" alt="" class="avatar-img">
|
||||||
<div class="avatar-glow"></div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="user-name"></div>
|
<div class="user-name">ZwaC</div>
|
||||||
<div class="user-location"></div>
|
<div class="user-location">南宁 · 在线</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="orbit-user" data-pos="6">
|
<div class="orbit-user" data-pos="6">
|
||||||
<div class="user-avatar glass">
|
<div class="user-avatar">
|
||||||
<img src="" alt="" class="avatar-img">
|
<img src="" alt="" class="avatar-img">
|
||||||
<div class="avatar-glow"></div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="user-name"></div>
|
<div class="user-name">小惠^</div>
|
||||||
<div class="user-location"></div>
|
<div class="user-location">崇左 · 在线</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<!-- 广告横幅 -->
|
||||||
|
<section class="promo-banner">
|
||||||
|
<img class="promo-icon-img" src="./images/promo_cards.png" alt="卡片" onerror="this.style.display='none'">
|
||||||
|
<span class="promo-text">语音加速卡折扣</span>
|
||||||
|
<span class="promo-link">加速卡/恋爱卡/魔仙卡 ></span>
|
||||||
|
<span class="promo-new">NEW</span>
|
||||||
|
</section>
|
||||||
|
|
||||||
<!-- 快捷操作按钮 -->
|
<!-- 快捷操作按钮 -->
|
||||||
<section class="quick-actions">
|
<section class="quick-actions">
|
||||||
<button class="action-btn neon-btn pink" id="voiceMatchBtn">
|
<button class="action-btn neon-btn pink" id="voiceMatchBtn">
|
||||||
<span class="btn-icon">🎧</span>
|
<span class="btn-icon">🎧</span>
|
||||||
<span class="btn-label">语音匹配</span>
|
<div class="btn-content">
|
||||||
|
<span class="btn-label">语音匹配</span>
|
||||||
|
<span class="btn-sub">今日剩9/10次</span>
|
||||||
|
</div>
|
||||||
</button>
|
</button>
|
||||||
<button class="action-btn neon-btn cyan" id="heartSignalBtn">
|
<button class="action-btn neon-btn cyan" id="heartSignalBtn">
|
||||||
<span class="btn-icon">💓</span>
|
<span class="btn-icon">💗</span>
|
||||||
<span class="btn-label">心动信号</span>
|
<div class="btn-content">
|
||||||
|
<span class="btn-label">心动信号</span>
|
||||||
|
<span class="btn-sub">已开启</span>
|
||||||
|
</div>
|
||||||
</button>
|
</button>
|
||||||
</section>
|
</section>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- 功能入口 2x3 -->
|
<!-- 可折叠底部面板 -->
|
||||||
<section class="feature-grid" id="categoryGrid">
|
<div class="bottom-sheet" id="bottomSheet">
|
||||||
<div class="feature-card glass" data-id="1">
|
<!-- 快速匹配玩伴 - 始终显示部分 -->
|
||||||
<div class="card-glow pink"></div>
|
<section class="sheet-section peek-section">
|
||||||
<div class="card-icon">💕</div>
|
<div class="sheet-handle" id="sheetHandle">
|
||||||
<div class="card-title">在线处对象</div>
|
<div class="handle-bar"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="feature-card glass" data-id="2">
|
<div class="section-header">
|
||||||
<div class="card-glow cyan"></div>
|
<span class="section-title">快速匹配玩伴</span>
|
||||||
<div class="card-icon">🎮</div>
|
<span class="section-more" id="expandBtn">上滑查看更多</span>
|
||||||
<div class="card-title">找人玩游戏</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="feature-card glass" data-id="3">
|
<div class="match-grid">
|
||||||
<div class="card-glow purple"></div>
|
<div class="match-card" data-category-id="1" data-category-name="在线处对象">
|
||||||
<div class="card-icon">🎤</div>
|
<div class="match-info">
|
||||||
<div class="card-title">一起KTV</div>
|
<span class="match-title">在线处对象</span>
|
||||||
</div>
|
<span class="match-desc">找个CP上上头</span>
|
||||||
<div class="feature-card glass" data-id="4">
|
</div>
|
||||||
<div class="card-glow pink"></div>
|
<span class="match-icon">💕</span>
|
||||||
<div class="card-icon">🎨</div>
|
</div>
|
||||||
<div class="card-title">你画我猜</div>
|
<div class="match-card" data-category-id="2" data-category-name="找人玩游戏">
|
||||||
</div>
|
<div class="match-info">
|
||||||
<div class="feature-card glass" data-id="5">
|
<span class="match-title">找人玩游戏</span>
|
||||||
<div class="card-glow cyan"></div>
|
<span class="match-desc">找游戏搭子</span>
|
||||||
<div class="card-icon">🔫</div>
|
</div>
|
||||||
<div class="card-title">和平精英</div>
|
<span class="match-icon">🎮</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="feature-card glass" data-id="6">
|
<div class="match-card" data-category-id="3" data-category-name="心动颜究所">
|
||||||
<div class="card-glow purple"></div>
|
<div class="match-info">
|
||||||
<div class="card-icon">🎲</div>
|
<span class="match-title">心动颜究所</span>
|
||||||
<div class="card-title">桌游派对</div>
|
<span class="match-desc">好看的人都在这</span>
|
||||||
|
</div>
|
||||||
|
<span class="match-icon">💗</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<!-- 底部面板内容 - 展开后显示 -->
|
||||||
|
<div class="sheet-content">
|
||||||
|
<!-- 派对 -->
|
||||||
|
<section class="sheet-section">
|
||||||
|
<div class="section-header">
|
||||||
|
<span class="section-title">派对</span>
|
||||||
|
</div>
|
||||||
|
<div class="party-grid">
|
||||||
|
<div class="party-card large" data-category-id="10" data-category-name="派对大厅">
|
||||||
|
<div class="party-bg pink"></div>
|
||||||
|
<div class="party-content">
|
||||||
|
<span class="party-title">派对大厅</span>
|
||||||
|
<span class="party-count">12345人在玩</span>
|
||||||
|
<span class="party-tag">快速进入</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="party-card" data-category-id="11" data-category-name="K歌房">
|
||||||
|
<div class="party-bg cyan"></div>
|
||||||
|
<div class="party-content">
|
||||||
|
<span class="party-title">K歌房</span>
|
||||||
|
<span class="party-desc">热门歌曲</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="party-card" data-category-id="12" data-category-name="游戏厅">
|
||||||
|
<div class="party-bg purple"></div>
|
||||||
|
<div class="party-content">
|
||||||
|
<span class="party-title">游戏厅</span>
|
||||||
|
<span class="party-desc">一起开黑</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="party-card" data-category-id="13" data-category-name="剧本杀">
|
||||||
|
<div class="party-bg orange"></div>
|
||||||
|
<div class="party-content">
|
||||||
|
<span class="party-title">剧本杀</span>
|
||||||
|
<span class="party-desc">烧脑推理</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="party-card" data-category-id="14" data-category-name="你画我猜">
|
||||||
|
<div class="party-bg green"></div>
|
||||||
|
<div class="party-content">
|
||||||
|
<span class="party-title">你画我猜</span>
|
||||||
|
<span class="party-desc">创意涂鸦</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- 小游戏 -->
|
||||||
|
<section class="sheet-section">
|
||||||
|
<div class="section-header">
|
||||||
|
<span class="section-title">小游戏</span>
|
||||||
|
</div>
|
||||||
|
<div class="game-list">
|
||||||
|
<div class="game-item" data-category-id="20" data-category-name="飞行棋">
|
||||||
|
<span class="game-name">飞行棋</span>
|
||||||
|
<span class="game-icon">🎲</span>
|
||||||
|
</div>
|
||||||
|
<div class="game-item" data-category-id="21" data-category-name="桌球">
|
||||||
|
<span class="game-name">桌球</span>
|
||||||
|
<span class="game-icon">🎱</span>
|
||||||
|
</div>
|
||||||
|
<div class="game-item" data-category-id="22" data-category-name="五子棋">
|
||||||
|
<span class="game-name">五子棋</span>
|
||||||
|
<span class="game-icon">⚫</span>
|
||||||
|
</div>
|
||||||
|
<div class="game-item" data-category-id="23" data-category-name="你画我猜">
|
||||||
|
<span class="game-name">你画我猜</span>
|
||||||
|
<span class="game-icon">🎨</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- 一起玩 -->
|
||||||
|
<section class="sheet-section">
|
||||||
|
<div class="section-header">
|
||||||
|
<span class="section-title">一起玩</span>
|
||||||
|
</div>
|
||||||
|
<div class="together-grid">
|
||||||
|
<div class="together-card" data-category-id="30" data-category-name="群聊广场">
|
||||||
|
<div class="together-icon">💬</div>
|
||||||
|
<div class="together-info">
|
||||||
|
<span class="together-title">群聊广场</span>
|
||||||
|
<span class="together-desc">31人在一起</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="together-card" data-category-id="31" data-category-name="游戏组队">
|
||||||
|
<div class="together-icon">👥</div>
|
||||||
|
<div class="together-info">
|
||||||
|
<span class="together-title">游戏组队</span>
|
||||||
|
<span class="together-desc">开黑上分</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="together-card" data-category-id="32" data-category-name="纸飞机">
|
||||||
|
<div class="together-icon">✈️</div>
|
||||||
|
<div class="together-info">
|
||||||
|
<span class="together-title">纸飞机</span>
|
||||||
|
<span class="together-desc">聊天匹配</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ public class DrawGuessActivity extends BaseCategoryActivity {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (id == R.id.nav_wish_tree) {
|
if (id == R.id.nav_wish_tree) {
|
||||||
WishTreeWebViewActivity.start(this);
|
WishTreeActivity.start(this);
|
||||||
finish();
|
finish();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -130,7 +130,7 @@ public class DynamicCommunityActivity extends AppCompatActivity {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (id == R.id.nav_wish_tree) {
|
if (id == R.id.nav_wish_tree) {
|
||||||
WishTreeWebViewActivity.start(this);
|
WishTreeActivity.start(this);
|
||||||
finish();
|
finish();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -194,7 +194,8 @@ public class FeedAdapter extends ListAdapter<FeedItem, RecyclerView.ViewHolder>
|
||||||
"title=" + work.getTitle() +
|
"title=" + work.getTitle() +
|
||||||
", userName=" + work.getUserName() +
|
", userName=" + work.getUserName() +
|
||||||
", authorName=" + work.getAuthorName() +
|
", authorName=" + work.getAuthorName() +
|
||||||
", likeCount=" + work.getLikeCount());
|
", likeCount=" + work.getLikeCount() +
|
||||||
|
", content=" + (work.getContent() != null ? work.getContent().substring(0, Math.min(50, work.getContent().length())) : "null"));
|
||||||
|
|
||||||
// 设置标题
|
// 设置标题
|
||||||
String title = work.getTitle();
|
String title = work.getTitle();
|
||||||
|
|
@ -255,27 +256,83 @@ public class FeedAdapter extends ListAdapter<FeedItem, RecyclerView.ViewHolder>
|
||||||
toggleWorkLike(work, !currentLiked, binding);
|
toggleWorkLike(work, !currentLiked, binding);
|
||||||
});
|
});
|
||||||
|
|
||||||
// 加载封面图片
|
// 判断是否为纯文字动态
|
||||||
String coverUrl = work.getCoverUrl();
|
String coverUrl = work.getCoverUrl();
|
||||||
if (coverUrl == null || coverUrl.trim().isEmpty()) {
|
String videoUrl = work.getVideoUrl();
|
||||||
// 如果没有封面,尝试使用第一张图片
|
boolean hasVideo = videoUrl != null && !videoUrl.trim().isEmpty();
|
||||||
if (work.getImageUrls() != null && !work.getImageUrls().isEmpty()) {
|
|
||||||
coverUrl = work.getImageUrls().get(0);
|
// 检查是否有有效的图片列表
|
||||||
|
boolean hasValidImageList = false;
|
||||||
|
if (work.getImageUrls() != null && !work.getImageUrls().isEmpty()) {
|
||||||
|
for (String imgUrl : work.getImageUrls()) {
|
||||||
|
if (imgUrl != null && !imgUrl.trim().isEmpty() && !isTextOnlyPlaceholder(imgUrl)) {
|
||||||
|
hasValidImageList = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取文字内容
|
||||||
|
String content = work.getContent();
|
||||||
|
if (content == null || content.trim().isEmpty()) {
|
||||||
|
content = work.getDescription();
|
||||||
|
}
|
||||||
|
boolean hasContent = content != null && !content.trim().isEmpty();
|
||||||
|
|
||||||
|
// 判断是否为纯文字动态:
|
||||||
|
// 核心逻辑:如果没有图片列表、没有视频,且有文字内容,就是纯文字动态
|
||||||
|
// 不管coverUrl是什么,因为后端可能给纯文字动态设置了一个无效的封面URL
|
||||||
|
boolean isTextOnly = !hasValidImageList && !hasVideo && hasContent;
|
||||||
|
|
||||||
|
// 检查封面是否为占位图(用于有图片的作品)
|
||||||
|
boolean isPlaceholderCover = isTextOnlyPlaceholder(coverUrl);
|
||||||
|
boolean hasCover = coverUrl != null && !coverUrl.trim().isEmpty() && !isPlaceholderCover;
|
||||||
|
|
||||||
|
// 如果没有封面,尝试使用第一张有效图片作为封面
|
||||||
|
String finalCoverUrl = coverUrl;
|
||||||
|
if (!hasCover && work.getImageUrls() != null) {
|
||||||
|
for (String imgUrl : work.getImageUrls()) {
|
||||||
|
if (imgUrl != null && !imgUrl.trim().isEmpty() && !isTextOnlyPlaceholder(imgUrl)) {
|
||||||
|
finalCoverUrl = imgUrl;
|
||||||
|
hasCover = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
android.util.Log.d("FeedAdapter", "作品类型判断: id=" + work.getId() +
|
||||||
|
", coverUrl=" + coverUrl +
|
||||||
|
", hasValidImageList=" + hasValidImageList +
|
||||||
|
", hasVideo=" + hasVideo +
|
||||||
|
", hasContent=" + hasContent +
|
||||||
|
", isTextOnly=" + isTextOnly);
|
||||||
|
|
||||||
|
final String finalContent = content;
|
||||||
|
if (isTextOnly) {
|
||||||
|
// 纯文字动态:隐藏封面区域,显示文字内容区域
|
||||||
|
binding.coverContainer.setVisibility(View.GONE);
|
||||||
|
binding.textContentContainer.setVisibility(View.VISIBLE);
|
||||||
|
binding.worksContentText.setText(finalContent);
|
||||||
|
|
||||||
|
android.util.Log.d("FeedAdapter", "显示纯文字动态: " + finalContent.substring(0, Math.min(30, finalContent.length())));
|
||||||
|
} else {
|
||||||
|
// 有封面的作品:显示封面区域,隐藏文字内容区域
|
||||||
|
binding.coverContainer.setVisibility(View.VISIBLE);
|
||||||
|
binding.textContentContainer.setVisibility(View.GONE);
|
||||||
|
|
||||||
|
if (hasCover && finalCoverUrl != null) {
|
||||||
|
Glide.with(binding.worksCoverImage)
|
||||||
|
.load(finalCoverUrl)
|
||||||
|
.placeholder(R.drawable.bg_cover_placeholder)
|
||||||
|
.centerCrop()
|
||||||
|
.into(binding.worksCoverImage);
|
||||||
|
} else {
|
||||||
|
binding.worksCoverImage.setImageResource(R.drawable.bg_cover_placeholder);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (coverUrl != null && !coverUrl.trim().isEmpty()) {
|
|
||||||
Glide.with(binding.worksCoverImage)
|
|
||||||
.load(coverUrl)
|
|
||||||
.placeholder(R.drawable.bg_cover_placeholder)
|
|
||||||
.centerCrop()
|
|
||||||
.into(binding.worksCoverImage);
|
|
||||||
} else {
|
|
||||||
binding.worksCoverImage.setImageResource(R.drawable.bg_cover_placeholder);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 显示作品类型图标(视频类型显示播放图标)
|
// 显示作品类型图标(视频类型显示播放图标)
|
||||||
if ("VIDEO".equals(work.getType())) {
|
if ("VIDEO".equals(work.getType()) || hasVideo) {
|
||||||
binding.worksTypeIcon.setVisibility(View.VISIBLE);
|
binding.worksTypeIcon.setVisibility(View.VISIBLE);
|
||||||
} else {
|
} else {
|
||||||
binding.worksTypeIcon.setVisibility(View.GONE);
|
binding.worksTypeIcon.setVisibility(View.GONE);
|
||||||
|
|
@ -430,4 +487,46 @@ public class FeedAdapter extends ListAdapter<FeedItem, RecyclerView.ViewHolder>
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断URL是否为纯文字动态的占位图
|
||||||
|
* 后端为纯文字动态设置的特殊封面地址
|
||||||
|
*/
|
||||||
|
private static boolean isTextOnlyPlaceholder(String url) {
|
||||||
|
if (url == null || url.trim().isEmpty()) {
|
||||||
|
return true; // 空URL也视为占位图
|
||||||
|
}
|
||||||
|
|
||||||
|
// 特殊占位图地址列表
|
||||||
|
String[] placeholderPatterns = {
|
||||||
|
"TEXT_ONLY_DYNAMIC_PLACEHOLDER", // Android端发布纯文字动态时设置的标识
|
||||||
|
"text_only_placeholder", // 纯文字动态占位图标识
|
||||||
|
"placeholder/text", // 文字占位图路径
|
||||||
|
"default_text_cover", // 默认文字封面
|
||||||
|
"no_image_placeholder", // 无图片占位图
|
||||||
|
"/placeholder.", // 通用占位图
|
||||||
|
"crmebimage/public/content/", // 后端默认内容图片路径
|
||||||
|
"default_cover", // 默认封面
|
||||||
|
"empty_cover", // 空封面
|
||||||
|
};
|
||||||
|
|
||||||
|
String lowerUrl = url.toLowerCase();
|
||||||
|
for (String pattern : placeholderPatterns) {
|
||||||
|
if (lowerUrl.contains(pattern.toLowerCase())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否为空白图片或默认图片(根据文件名判断)
|
||||||
|
if (lowerUrl.endsWith("/default.png") ||
|
||||||
|
lowerUrl.endsWith("/default.jpg") ||
|
||||||
|
lowerUrl.endsWith("/placeholder.png") ||
|
||||||
|
lowerUrl.endsWith("/placeholder.jpg") ||
|
||||||
|
lowerUrl.endsWith("/empty.png") ||
|
||||||
|
lowerUrl.endsWith("/empty.jpg")) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@ public class FindGameActivity extends BaseCategoryActivity {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (id == R.id.nav_wish_tree) {
|
if (id == R.id.nav_wish_tree) {
|
||||||
WishTreeWebViewActivity.start(this);
|
WishTreeActivity.start(this);
|
||||||
finish();
|
finish();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -139,7 +139,7 @@ public class FishPondActivity extends AppCompatActivity {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (id == R.id.nav_wish_tree) {
|
if (id == R.id.nav_wish_tree) {
|
||||||
WishTreeWebViewActivity.start(this);
|
WishTreeActivity.start(this);
|
||||||
finish();
|
finish();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -133,7 +133,7 @@ public class FishPondWebViewActivity extends AppCompatActivity {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (id == R.id.nav_wish_tree) {
|
if (id == R.id.nav_wish_tree) {
|
||||||
WishTreeWebViewActivity.start(this);
|
WishTreeActivity.start(this);
|
||||||
finish();
|
finish();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -107,7 +107,7 @@ public class HeartbeatSignalActivity extends AppCompatActivity {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (id == R.id.nav_wish_tree) {
|
if (id == R.id.nav_wish_tree) {
|
||||||
WishTreeWebViewActivity.start(this);
|
WishTreeActivity.start(this);
|
||||||
finish();
|
finish();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ public class KTVTogetherActivity extends BaseCategoryActivity {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (id == R.id.nav_wish_tree) {
|
if (id == R.id.nav_wish_tree) {
|
||||||
WishTreeWebViewActivity.start(this);
|
WishTreeActivity.start(this);
|
||||||
finish();
|
finish();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,19 +3,32 @@ package com.example.livestreaming;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.View;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
|
|
||||||
import com.example.livestreaming.databinding.ActivityLikesListBinding;
|
import com.example.livestreaming.databinding.ActivityLikesListBinding;
|
||||||
|
import com.example.livestreaming.net.ApiClient;
|
||||||
|
import com.example.livestreaming.net.ApiResponse;
|
||||||
|
import com.example.livestreaming.net.PageResponse;
|
||||||
|
import com.example.livestreaming.net.WorksResponse;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import retrofit2.Call;
|
||||||
|
import retrofit2.Callback;
|
||||||
|
import retrofit2.Response;
|
||||||
|
|
||||||
public class LikesListActivity extends AppCompatActivity {
|
public class LikesListActivity extends AppCompatActivity {
|
||||||
|
|
||||||
|
private static final String TAG = "LikesListActivity";
|
||||||
private ActivityLikesListBinding binding;
|
private ActivityLikesListBinding binding;
|
||||||
|
private ConversationsAdapter adapter;
|
||||||
|
|
||||||
public static void start(Context context) {
|
public static void start(Context context) {
|
||||||
Intent intent = new Intent(context, LikesListActivity.class);
|
Intent intent = new Intent(context, LikesListActivity.class);
|
||||||
|
|
@ -30,28 +43,100 @@ public class LikesListActivity extends AppCompatActivity {
|
||||||
|
|
||||||
binding.backButton.setOnClickListener(v -> finish());
|
binding.backButton.setOnClickListener(v -> finish());
|
||||||
|
|
||||||
ConversationsAdapter adapter = new ConversationsAdapter(item -> {
|
adapter = new ConversationsAdapter(item -> {
|
||||||
if (item == null) return;
|
if (item == null) return;
|
||||||
Toast.makeText(this, "查看获赞:" + item.getTitle(), Toast.LENGTH_SHORT).show();
|
// 点击跳转到作品详情
|
||||||
|
if (item.getId() != null && !item.getId().isEmpty()) {
|
||||||
|
WorkDetailActivity.start(this, item.getId(), false);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// TODO: 接入后端接口 - 获取获赞列表
|
|
||||||
// 接口路径: GET /api/likes
|
|
||||||
// 请求参数:
|
|
||||||
// - userId: 当前用户ID(从token中获取)
|
|
||||||
// - page (可选): 页码
|
|
||||||
// - pageSize (可选): 每页数量
|
|
||||||
// 返回数据格式: ApiResponse<List<LikeItem>>
|
|
||||||
// LikeItem对象应包含: id, userId, username, avatarUrl, targetType (room/work), targetId, targetTitle, likeTime等字段
|
|
||||||
// 列表应按点赞时间倒序排列(最新点赞的在前面)
|
|
||||||
binding.likesRecyclerView.setLayoutManager(new LinearLayoutManager(this));
|
binding.likesRecyclerView.setLayoutManager(new LinearLayoutManager(this));
|
||||||
binding.likesRecyclerView.setAdapter(adapter);
|
binding.likesRecyclerView.setAdapter(adapter);
|
||||||
adapter.submitList(buildDemoLikes());
|
|
||||||
|
// 加载获赞数据
|
||||||
|
loadLikesData();
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<ConversationItem> buildDemoLikes() {
|
private void loadLikesData() {
|
||||||
List<ConversationItem> list = new ArrayList<>();
|
if (!AuthHelper.isLoggedIn(this)) {
|
||||||
// 不再使用模拟数据,只从后端接口获取真实点赞数据
|
showEmptyState();
|
||||||
return list;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取当前用户ID
|
||||||
|
String userIdStr = com.example.livestreaming.net.AuthStore.getUserId(this);
|
||||||
|
if (userIdStr == null || userIdStr.isEmpty()) {
|
||||||
|
showEmptyState();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int userId;
|
||||||
|
try {
|
||||||
|
userId = Integer.parseInt(userIdStr);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
showEmptyState();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取用户的所有作品及其点赞信息
|
||||||
|
ApiClient.getService(this).getUserWorks(userId, 1, 100)
|
||||||
|
.enqueue(new Callback<ApiResponse<PageResponse<WorksResponse>>>() {
|
||||||
|
@Override
|
||||||
|
public void onResponse(Call<ApiResponse<PageResponse<WorksResponse>>> call,
|
||||||
|
Response<ApiResponse<PageResponse<WorksResponse>>> response) {
|
||||||
|
if (response.isSuccessful() && response.body() != null && response.body().isOk()) {
|
||||||
|
PageResponse<WorksResponse> pageData = response.body().getData();
|
||||||
|
if (pageData != null && pageData.getList() != null && !pageData.getList().isEmpty()) {
|
||||||
|
List<ConversationItem> items = convertWorksToLikeItems(pageData.getList());
|
||||||
|
if (!items.isEmpty()) {
|
||||||
|
adapter.submitList(items);
|
||||||
|
showContent();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
showEmptyState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Call<ApiResponse<PageResponse<WorksResponse>>> call, Throwable t) {
|
||||||
|
Log.e(TAG, "加载获赞数据失败: " + t.getMessage());
|
||||||
|
showEmptyState();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将作品列表转换为点赞项列表(只显示有点赞的作品)
|
||||||
|
*/
|
||||||
|
private List<ConversationItem> convertWorksToLikeItems(List<WorksResponse> works) {
|
||||||
|
List<ConversationItem> items = new ArrayList<>();
|
||||||
|
for (WorksResponse work : works) {
|
||||||
|
Integer likeCount = work.getLikeCount();
|
||||||
|
if (likeCount != null && likeCount > 0) {
|
||||||
|
String id = String.valueOf(work.getId());
|
||||||
|
String title = work.getTitle() != null ? work.getTitle() : "作品";
|
||||||
|
String lastMessage = likeCount + "人点赞了这个作品";
|
||||||
|
String timeText = "";
|
||||||
|
|
||||||
|
ConversationItem item = new ConversationItem(id, title, lastMessage, timeText, likeCount, false);
|
||||||
|
item.setAvatarUrl(work.getCoverUrl());
|
||||||
|
items.add(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showEmptyState() {
|
||||||
|
// 显示空状态
|
||||||
|
adapter.submitList(new ArrayList<>());
|
||||||
|
binding.likesRecyclerView.setVisibility(View.GONE);
|
||||||
|
binding.emptyView.setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showContent() {
|
||||||
|
binding.likesRecyclerView.setVisibility(View.VISIBLE);
|
||||||
|
binding.emptyView.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -550,8 +550,13 @@ public class MainActivity extends AppCompatActivity {
|
||||||
// 加载热门作品
|
// 加载热门作品
|
||||||
refreshHotWorks();
|
refreshHotWorks();
|
||||||
} else {
|
} else {
|
||||||
// 应用其他分类筛选(带动画)
|
// 如果数据为空,先加载数据
|
||||||
applyCategoryFilterWithAnimation(currentCategory);
|
if (allFeedItems.isEmpty()) {
|
||||||
|
fetchDiscoverRooms();
|
||||||
|
} else {
|
||||||
|
// 应用其他分类筛选(带动画)
|
||||||
|
applyCategoryFilterWithAnimation(currentCategory);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -572,8 +577,13 @@ public class MainActivity extends AppCompatActivity {
|
||||||
// 刷新热门作品
|
// 刷新热门作品
|
||||||
refreshHotWorks();
|
refreshHotWorks();
|
||||||
} else {
|
} else {
|
||||||
// 应用其他分类筛选(带动画)
|
// 如果数据为空,先加载数据;否则刷新
|
||||||
applyCategoryFilterWithAnimation(currentCategory);
|
if (allFeedItems.isEmpty()) {
|
||||||
|
fetchDiscoverRooms();
|
||||||
|
} else {
|
||||||
|
// 重新加载数据
|
||||||
|
fetchDiscoverRooms();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -609,7 +619,8 @@ public class MainActivity extends AppCompatActivity {
|
||||||
binding.fabAddLive.setOnClickListener(new DebounceClickListener() {
|
binding.fabAddLive.setOnClickListener(new DebounceClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onDebouncedClick(View v) {
|
public void onDebouncedClick(View v) {
|
||||||
showCreateRoomDialog();
|
// 跳转到发布中心页面
|
||||||
|
PublishCenterActivity.start(MainActivity.this);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -633,7 +644,7 @@ public class MainActivity extends AppCompatActivity {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (id == R.id.nav_wish_tree) {
|
if (id == R.id.nav_wish_tree) {
|
||||||
WishTreeWebViewActivity.start(this);
|
WishTreeActivity.start(this);
|
||||||
finish();
|
finish();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -1882,62 +1893,95 @@ public class MainActivity extends AppCompatActivity {
|
||||||
// 增加请求ID,确保只有最新的筛选结果被应用
|
// 增加请求ID,确保只有最新的筛选结果被应用
|
||||||
final int requestId = ++filterRequestId;
|
final int requestId = ++filterRequestId;
|
||||||
|
|
||||||
|
// 如果是"推荐"或"全部",显示所有数据
|
||||||
|
if ("推荐".equals(c) || "全部".equals(c)) {
|
||||||
|
binding.roomsRecyclerView.animate()
|
||||||
|
.alpha(0.7f)
|
||||||
|
.setDuration(100)
|
||||||
|
.withEndAction(() -> {
|
||||||
|
if (requestId != filterRequestId) return;
|
||||||
|
|
||||||
|
adapter.submitList(new ArrayList<>(allFeedItems), () -> {
|
||||||
|
if (requestId != filterRequestId) return;
|
||||||
|
binding.roomsRecyclerView.animate()
|
||||||
|
.alpha(1.0f)
|
||||||
|
.setDuration(200)
|
||||||
|
.start();
|
||||||
|
});
|
||||||
|
|
||||||
|
if (allFeedItems.isEmpty()) {
|
||||||
|
showEmptyState("暂无内容");
|
||||||
|
} else {
|
||||||
|
hideEmptyState();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.start();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// 显示加载状态(如果数据量较大)
|
// 显示加载状态(如果数据量较大)
|
||||||
if (allRooms.size() > 50) {
|
if (allFeedItems.size() > 50) {
|
||||||
binding.loading.setVisibility(View.VISIBLE);
|
binding.loading.setVisibility(View.VISIBLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 使用筛选管理器异步筛选
|
// 筛选FeedItem列表
|
||||||
if (filterManager != null) {
|
List<FeedItem> filtered = new ArrayList<>();
|
||||||
filterManager.filterRoomsAsync(allRooms, c, filteredRooms -> {
|
for (FeedItem item : allFeedItems) {
|
||||||
// 检查这个结果是否仍然是最新的请求
|
if (item == null) continue;
|
||||||
if (requestId != filterRequestId) {
|
|
||||||
// 这是一个旧的请求结果,忽略它
|
// 根据类型获取分类
|
||||||
return;
|
String itemCategory = null;
|
||||||
|
if (item.getType() == FeedItem.TYPE_ROOM && item.getRoom() != null) {
|
||||||
|
Room room = item.getRoom();
|
||||||
|
itemCategory = room.getCategoryName();
|
||||||
|
if (itemCategory == null || itemCategory.isEmpty()) {
|
||||||
|
itemCategory = room.getType();
|
||||||
}
|
}
|
||||||
|
} else if (item.getType() == FeedItem.TYPE_WORK && item.getWork() != null) {
|
||||||
// 隐藏加载状态
|
// 作品按分类筛选
|
||||||
binding.loading.setVisibility(View.GONE);
|
WorksResponse work = item.getWork();
|
||||||
|
itemCategory = work.getCategoryName();
|
||||||
// 添加淡入动画
|
if (itemCategory == null || itemCategory.isEmpty()) {
|
||||||
binding.roomsRecyclerView.animate()
|
itemCategory = work.getCategory();
|
||||||
.alpha(0.7f)
|
}
|
||||||
.setDuration(100)
|
} else if (item.getType() == FeedItem.TYPE_CHATROOM) {
|
||||||
.withEndAction(() -> {
|
// 聊天室暂时不按分类筛选,全部显示
|
||||||
// 再次检查请求ID(防止在动画期间又有新的筛选请求)
|
filtered.add(item);
|
||||||
if (requestId != filterRequestId) {
|
continue;
|
||||||
return;
|
}
|
||||||
}
|
|
||||||
|
// 如果分类匹配,添加到筛选结果
|
||||||
// 转换为FeedItem列表
|
if (c.equals(itemCategory)) {
|
||||||
List<FeedItem> feedItems = new ArrayList<>();
|
filtered.add(item);
|
||||||
for (Room room : filteredRooms) {
|
}
|
||||||
feedItems.add(FeedItem.fromRoom(room));
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新列表数据(ListAdapter会自动处理DiffUtil动画)
|
|
||||||
adapter.submitList(feedItems, () -> {
|
|
||||||
// 最后一次检查请求ID
|
|
||||||
if (requestId != filterRequestId) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 数据更新完成后,恢复透明度并添加淡入效果
|
|
||||||
binding.roomsRecyclerView.animate()
|
|
||||||
.alpha(1.0f)
|
|
||||||
.setDuration(200)
|
|
||||||
.start();
|
|
||||||
});
|
|
||||||
|
|
||||||
// 更新空状态
|
|
||||||
updateEmptyStateForList(filteredRooms);
|
|
||||||
})
|
|
||||||
.start();
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
// 降级到同步筛选(如果筛选管理器未初始化)
|
|
||||||
applyCategoryFilterSync(c);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 隐藏加载状态
|
||||||
|
binding.loading.setVisibility(View.GONE);
|
||||||
|
|
||||||
|
// 添加淡入动画
|
||||||
|
final List<FeedItem> finalFiltered = filtered;
|
||||||
|
binding.roomsRecyclerView.animate()
|
||||||
|
.alpha(0.7f)
|
||||||
|
.setDuration(100)
|
||||||
|
.withEndAction(() -> {
|
||||||
|
if (requestId != filterRequestId) return;
|
||||||
|
|
||||||
|
adapter.submitList(finalFiltered, () -> {
|
||||||
|
if (requestId != filterRequestId) return;
|
||||||
|
binding.roomsRecyclerView.animate()
|
||||||
|
.alpha(1.0f)
|
||||||
|
.setDuration(200)
|
||||||
|
.start();
|
||||||
|
});
|
||||||
|
|
||||||
|
if (finalFiltered.isEmpty()) {
|
||||||
|
showEmptyState("该分类暂无内容");
|
||||||
|
} else {
|
||||||
|
hideEmptyState();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -2528,8 +2572,15 @@ public class MainActivity extends AppCompatActivity {
|
||||||
Log.d(TAG, "checkAndDisplayFeed() 提交 " + allFeedItems.size() + " 项到适配器");
|
Log.d(TAG, "checkAndDisplayFeed() 提交 " + allFeedItems.size() + " 项到适配器");
|
||||||
hideEmptyState();
|
hideEmptyState();
|
||||||
if (binding.loading != null) binding.loading.setVisibility(View.GONE);
|
if (binding.loading != null) binding.loading.setVisibility(View.GONE);
|
||||||
// 提交数据到适配器
|
|
||||||
adapter.submitList(new ArrayList<>(allFeedItems));
|
// 根据当前分类筛选数据
|
||||||
|
if ("热门".equals(currentCategory)) {
|
||||||
|
// 热门分类使用热门作品数据
|
||||||
|
// 不做任何操作,热门数据由 refreshHotWorks 加载
|
||||||
|
} else {
|
||||||
|
// 其他分类应用筛选
|
||||||
|
applyCategoryFilterWithAnimation(currentCategory);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新发现页面的空状态
|
// 更新发现页面的空状态
|
||||||
|
|
@ -2854,6 +2905,11 @@ public class MainActivity extends AppCompatActivity {
|
||||||
binding.roomsRecyclerView.setVisibility(View.VISIBLE);
|
binding.roomsRecyclerView.setVisibility(View.VISIBLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 预加载所有作品和直播间数据(用于其他分类筛选)
|
||||||
|
if (allFeedItems.isEmpty()) {
|
||||||
|
fetchDiscoverRooms();
|
||||||
|
}
|
||||||
|
|
||||||
// 使用房间适配器显示推荐内容
|
// 使用房间适配器显示推荐内容
|
||||||
if (adapter != null) {
|
if (adapter != null) {
|
||||||
// 默认选中"热门"Tab并加载热门作品
|
// 默认选中"热门"Tab并加载热门作品
|
||||||
|
|
@ -4140,9 +4196,26 @@ public class MainActivity extends AppCompatActivity {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 从本地加载我的频道配置
|
* 从本地加载我的频道配置
|
||||||
|
* 注意:如果本地配置的分类名称与后端不匹配,需要重置为默认配置
|
||||||
*/
|
*/
|
||||||
private void loadMyChannelsFromPrefs() {
|
private void loadMyChannelsFromPrefs() {
|
||||||
android.content.SharedPreferences prefs = getSharedPreferences("channel_prefs", MODE_PRIVATE);
|
android.content.SharedPreferences prefs = getSharedPreferences("channel_prefs", MODE_PRIVATE);
|
||||||
|
|
||||||
|
// 检查配置版本,如果版本不匹配则重置配置
|
||||||
|
int configVersion = prefs.getInt("channel_config_version", 0);
|
||||||
|
int currentVersion = 2; // 版本2:分类名称与后端匹配(娱乐、游戏、音乐、户外)
|
||||||
|
|
||||||
|
if (configVersion < currentVersion) {
|
||||||
|
// 版本不匹配,清除旧配置,使用新的默认配置
|
||||||
|
Log.d(TAG, "频道配置版本过旧(" + configVersion + " < " + currentVersion + "),重置为默认配置");
|
||||||
|
prefs.edit()
|
||||||
|
.remove("my_channels")
|
||||||
|
.putInt("channel_config_version", currentVersion)
|
||||||
|
.apply();
|
||||||
|
initDefaultMyChannels();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
String channelsJson = prefs.getString("my_channels", "");
|
String channelsJson = prefs.getString("my_channels", "");
|
||||||
|
|
||||||
if (!channelsJson.isEmpty()) {
|
if (!channelsJson.isEmpty()) {
|
||||||
|
|
@ -4179,14 +4252,17 @@ public class MainActivity extends AppCompatActivity {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 初始化默认的我的频道配置
|
* 初始化默认的我的频道配置
|
||||||
|
* 注意:分类名称必须与后端数据库 eb_live_room_category 表中的 name 字段一致
|
||||||
|
* 后端分类:娱乐、游戏、音乐、户外、美食、体育、教育、科技
|
||||||
*/
|
*/
|
||||||
private void initDefaultMyChannels() {
|
private void initDefaultMyChannels() {
|
||||||
myChannels.clear();
|
myChannels.clear();
|
||||||
myChannels.add(new ChannelTagAdapter.ChannelTag(0, "推荐"));
|
myChannels.add(new ChannelTagAdapter.ChannelTag(0, "推荐"));
|
||||||
myChannels.add(new ChannelTagAdapter.ChannelTag(1, "直播"));
|
myChannels.add(new ChannelTagAdapter.ChannelTag(1, "娱乐"));
|
||||||
myChannels.add(new ChannelTagAdapter.ChannelTag(2, "视频"));
|
myChannels.add(new ChannelTagAdapter.ChannelTag(2, "游戏"));
|
||||||
myChannels.add(new ChannelTagAdapter.ChannelTag(3, "音乐"));
|
myChannels.add(new ChannelTagAdapter.ChannelTag(3, "音乐"));
|
||||||
Log.d(TAG, "使用默认我的频道配置");
|
myChannels.add(new ChannelTagAdapter.ChannelTag(4, "户外"));
|
||||||
|
Log.d(TAG, "使用默认我的频道配置(与后端分类匹配)");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -108,7 +108,7 @@ public class MessagesActivity extends AppCompatActivity {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (id == R.id.nav_wish_tree) {
|
if (id == R.id.nav_wish_tree) {
|
||||||
WishTreeWebViewActivity.start(this);
|
WishTreeActivity.start(this);
|
||||||
finish();
|
finish();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ public class OnlineDatingActivity extends BaseCategoryActivity {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (id == R.id.nav_wish_tree) {
|
if (id == R.id.nav_wish_tree) {
|
||||||
WishTreeWebViewActivity.start(this);
|
WishTreeActivity.start(this);
|
||||||
finish();
|
finish();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ public class PeaceEliteActivity extends BaseCategoryActivity {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (id == R.id.nav_wish_tree) {
|
if (id == R.id.nav_wish_tree) {
|
||||||
WishTreeWebViewActivity.start(this);
|
WishTreeActivity.start(this);
|
||||||
finish();
|
finish();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -146,7 +146,7 @@ public class ProfileActivity extends AppCompatActivity {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (id == R.id.nav_wish_tree) {
|
if (id == R.id.nav_wish_tree) {
|
||||||
WishTreeWebViewActivity.start(this);
|
WishTreeActivity.start(this);
|
||||||
finish();
|
finish();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -440,11 +440,11 @@ public class ProfileActivity extends AppCompatActivity {
|
||||||
startActivity(new Intent(this, FollowingActivity.class));
|
startActivity(new Intent(this, FollowingActivity.class));
|
||||||
});
|
});
|
||||||
binding.action2.setOnClickListener(v -> {
|
binding.action2.setOnClickListener(v -> {
|
||||||
// 我的点赞(作品+直播间)
|
// 我的好友
|
||||||
if (!AuthHelper.requireLogin(this, "查看点赞需要登录")) {
|
if (!AuthHelper.requireLogin(this, "查看好友列表需要登录")) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
MyLikesActivity.start(this);
|
startActivity(new Intent(this, MyFriendsActivity.class));
|
||||||
});
|
});
|
||||||
binding.action3.setOnClickListener(v -> {
|
binding.action3.setOnClickListener(v -> {
|
||||||
// 我的收藏(作品+直播间)
|
// 我的收藏(作品+直播间)
|
||||||
|
|
@ -453,13 +453,6 @@ public class ProfileActivity extends AppCompatActivity {
|
||||||
}
|
}
|
||||||
MyCollectionsActivity.start(this);
|
MyCollectionsActivity.start(this);
|
||||||
});
|
});
|
||||||
binding.action4.setOnClickListener(v -> {
|
|
||||||
// 我的记录 - 跳转到统一记录页面
|
|
||||||
if (!AuthHelper.requireLogin(this, "查看记录需要登录")) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
MyRecordsActivity.start(this);
|
|
||||||
});
|
|
||||||
|
|
||||||
binding.editProfile.setOnClickListener(v -> {
|
binding.editProfile.setOnClickListener(v -> {
|
||||||
// 检查登录状态,编辑资料需要登录
|
// 检查登录状态,编辑资料需要登录
|
||||||
|
|
@ -539,7 +532,7 @@ public class ProfileActivity extends AppCompatActivity {
|
||||||
if (!AuthHelper.requireLogin(this, "发布作品需要登录")) {
|
if (!AuthHelper.requireLogin(this, "发布作品需要登录")) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
PublishWorkActivity.start(this);
|
PublishCenterActivity.start(this);
|
||||||
});
|
});
|
||||||
|
|
||||||
// 悬浮按钮(固定显示)
|
// 悬浮按钮(固定显示)
|
||||||
|
|
@ -548,7 +541,7 @@ public class ProfileActivity extends AppCompatActivity {
|
||||||
if (!AuthHelper.requireLogin(this, "发布作品需要登录")) {
|
if (!AuthHelper.requireLogin(this, "发布作品需要登录")) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
PublishWorkActivity.start(this);
|
PublishCenterActivity.start(this);
|
||||||
});
|
});
|
||||||
binding.likedGoBrowseBtn.setOnClickListener(v -> startActivity(new Intent(this, MainActivity.class)));
|
binding.likedGoBrowseBtn.setOnClickListener(v -> startActivity(new Intent(this, MainActivity.class)));
|
||||||
binding.favGoBrowseBtn.setOnClickListener(v -> startActivity(new Intent(this, MainActivity.class)));
|
binding.favGoBrowseBtn.setOnClickListener(v -> startActivity(new Intent(this, MainActivity.class)));
|
||||||
|
|
@ -573,15 +566,150 @@ public class ProfileActivity extends AppCompatActivity {
|
||||||
binding.myWorksRecycler.setLayoutManager(new GridLayoutManager(this, 2));
|
binding.myWorksRecycler.setLayoutManager(new GridLayoutManager(this, 2));
|
||||||
binding.myWorksRecycler.setAdapter(myWorksAdapter);
|
binding.myWorksRecycler.setAdapter(myWorksAdapter);
|
||||||
|
|
||||||
|
// 设置赞过列表
|
||||||
|
likedWorksAdapter = new WorksAdapter(work -> {
|
||||||
|
if (work != null && work.getId() != null) {
|
||||||
|
WorkDetailActivity.start(this, String.valueOf(work.getId()), false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
binding.likedWorksRecycler.setLayoutManager(new GridLayoutManager(this, 2));
|
||||||
|
binding.likedWorksRecycler.setAdapter(likedWorksAdapter);
|
||||||
|
|
||||||
|
// 设置收藏列表
|
||||||
|
collectedWorksAdapter = new WorksAdapter(work -> {
|
||||||
|
if (work != null && work.getId() != null) {
|
||||||
|
WorkDetailActivity.start(this, String.valueOf(work.getId()), false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
binding.collectedWorksRecycler.setLayoutManager(new GridLayoutManager(this, 2));
|
||||||
|
binding.collectedWorksRecycler.setAdapter(collectedWorksAdapter);
|
||||||
|
|
||||||
|
// Tab切换点击事件
|
||||||
|
binding.tabWorks.setOnClickListener(v -> switchToTab(0));
|
||||||
|
binding.tabLiked.setOnClickListener(v -> switchToTab(1));
|
||||||
|
binding.tabCollected.setOnClickListener(v -> switchToTab(2));
|
||||||
|
|
||||||
// 发布按钮点击事件
|
// 发布按钮点击事件
|
||||||
binding.myWorksPublishBtn.setOnClickListener(v -> {
|
binding.myWorksPublishBtn.setOnClickListener(v -> {
|
||||||
if (!AuthHelper.requireLogin(this, "发布作品需要登录")) {
|
if (!AuthHelper.requireLogin(this, "发布作品需要登录")) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
PublishWorkActivity.start(this);
|
PublishCenterActivity.start(this);
|
||||||
});
|
});
|
||||||
|
|
||||||
loadMyWorks();
|
// 默认显示作品Tab
|
||||||
|
switchToTab(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int currentWorksTab = 0;
|
||||||
|
private WorksAdapter likedWorksAdapter;
|
||||||
|
private WorksAdapter collectedWorksAdapter;
|
||||||
|
|
||||||
|
private void switchToTab(int tabIndex) {
|
||||||
|
currentWorksTab = tabIndex;
|
||||||
|
|
||||||
|
// 更新Tab样式
|
||||||
|
binding.tabWorks.setTextColor(tabIndex == 0 ? 0xFF111111 : 0xFF999999);
|
||||||
|
binding.tabWorks.setTypeface(null, tabIndex == 0 ? android.graphics.Typeface.BOLD : android.graphics.Typeface.NORMAL);
|
||||||
|
binding.tabLiked.setTextColor(tabIndex == 1 ? 0xFF111111 : 0xFF999999);
|
||||||
|
binding.tabLiked.setTypeface(null, tabIndex == 1 ? android.graphics.Typeface.BOLD : android.graphics.Typeface.NORMAL);
|
||||||
|
binding.tabCollected.setTextColor(tabIndex == 2 ? 0xFF111111 : 0xFF999999);
|
||||||
|
binding.tabCollected.setTypeface(null, tabIndex == 2 ? android.graphics.Typeface.BOLD : android.graphics.Typeface.NORMAL);
|
||||||
|
|
||||||
|
// 隐藏所有列表
|
||||||
|
binding.myWorksRecycler.setVisibility(View.GONE);
|
||||||
|
binding.likedWorksRecycler.setVisibility(View.GONE);
|
||||||
|
binding.collectedWorksRecycler.setVisibility(View.GONE);
|
||||||
|
binding.myWorksEmptyState.setVisibility(View.GONE);
|
||||||
|
|
||||||
|
// 根据Tab加载数据
|
||||||
|
switch (tabIndex) {
|
||||||
|
case 0:
|
||||||
|
loadMyWorks();
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
loadLikedWorks();
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
loadCollectedWorks();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadLikedWorks() {
|
||||||
|
if (!AuthHelper.isLoggedIn(this)) {
|
||||||
|
showEmptyState("赞过", "还没有点赞作品", false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 调用获取我点赞的作品列表API
|
||||||
|
ApiClient.getService(this).getMyLikedWorks(1, 50).enqueue(new Callback<ApiResponse<PageResponse<WorksResponse>>>() {
|
||||||
|
@Override
|
||||||
|
public void onResponse(Call<ApiResponse<PageResponse<WorksResponse>>> call,
|
||||||
|
Response<ApiResponse<PageResponse<WorksResponse>>> response) {
|
||||||
|
if (response.isSuccessful() && response.body() != null && response.body().isOk()) {
|
||||||
|
PageResponse<WorksResponse> pageData = response.body().getData();
|
||||||
|
if (pageData != null && pageData.getList() != null && !pageData.getList().isEmpty()) {
|
||||||
|
List<WorksResponse> likedWorks = pageData.getList();
|
||||||
|
binding.likedWorksRecycler.setVisibility(View.VISIBLE);
|
||||||
|
binding.myWorksEmptyState.setVisibility(View.GONE);
|
||||||
|
binding.myWorksCount.setText(likedWorks.size() + "个赞过");
|
||||||
|
likedWorksAdapter.submitList(likedWorks);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
showEmptyState("赞过", "还没有点赞作品", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Call<ApiResponse<PageResponse<WorksResponse>>> call, Throwable t) {
|
||||||
|
Log.e(TAG, "加载点赞作品失败: " + t.getMessage());
|
||||||
|
showEmptyState("赞过", "还没有点赞作品", false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadCollectedWorks() {
|
||||||
|
if (!AuthHelper.isLoggedIn(this)) {
|
||||||
|
showEmptyState("收藏", "还没有收藏作品", false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 调用获取我收藏的作品列表API
|
||||||
|
ApiClient.getService(this).getMyCollectedWorks(1, 50).enqueue(new Callback<ApiResponse<PageResponse<WorksResponse>>>() {
|
||||||
|
@Override
|
||||||
|
public void onResponse(Call<ApiResponse<PageResponse<WorksResponse>>> call,
|
||||||
|
Response<ApiResponse<PageResponse<WorksResponse>>> response) {
|
||||||
|
if (response.isSuccessful() && response.body() != null && response.body().isOk()) {
|
||||||
|
PageResponse<WorksResponse> pageData = response.body().getData();
|
||||||
|
if (pageData != null && pageData.getList() != null && !pageData.getList().isEmpty()) {
|
||||||
|
List<WorksResponse> collectedWorks = pageData.getList();
|
||||||
|
binding.collectedWorksRecycler.setVisibility(View.VISIBLE);
|
||||||
|
binding.myWorksEmptyState.setVisibility(View.GONE);
|
||||||
|
binding.myWorksCount.setText(collectedWorks.size() + "个收藏");
|
||||||
|
collectedWorksAdapter.submitList(collectedWorks);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
showEmptyState("收藏", "还没有收藏作品", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Call<ApiResponse<PageResponse<WorksResponse>>> call, Throwable t) {
|
||||||
|
Log.e(TAG, "加载收藏作品失败: " + t.getMessage());
|
||||||
|
showEmptyState("收藏", "还没有收藏作品", false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showEmptyState(String tabName, String message, boolean showPublishBtn) {
|
||||||
|
binding.myWorksRecycler.setVisibility(View.GONE);
|
||||||
|
binding.likedWorksRecycler.setVisibility(View.GONE);
|
||||||
|
binding.collectedWorksRecycler.setVisibility(View.GONE);
|
||||||
|
binding.myWorksEmptyState.setVisibility(View.VISIBLE);
|
||||||
|
binding.emptyStateText.setText(message);
|
||||||
|
binding.myWorksPublishBtn.setVisibility(showPublishBtn ? View.VISIBLE : View.GONE);
|
||||||
|
binding.myWorksCount.setText("0个" + tabName);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadMyWorks() {
|
private void loadMyWorks() {
|
||||||
|
|
@ -642,7 +770,11 @@ public class ProfileActivity extends AppCompatActivity {
|
||||||
|
|
||||||
private void showMyWorksEmpty() {
|
private void showMyWorksEmpty() {
|
||||||
binding.myWorksRecycler.setVisibility(View.GONE);
|
binding.myWorksRecycler.setVisibility(View.GONE);
|
||||||
|
binding.likedWorksRecycler.setVisibility(View.GONE);
|
||||||
|
binding.collectedWorksRecycler.setVisibility(View.GONE);
|
||||||
binding.myWorksEmptyState.setVisibility(View.VISIBLE);
|
binding.myWorksEmptyState.setVisibility(View.VISIBLE);
|
||||||
|
binding.emptyStateText.setText("还没有发布作品");
|
||||||
|
binding.myWorksPublishBtn.setVisibility(View.VISIBLE);
|
||||||
binding.myWorksCount.setText("0个作品");
|
binding.myWorksCount.setText("0个作品");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -675,9 +807,9 @@ public class ProfileActivity extends AppCompatActivity {
|
||||||
// - pageSize (可选): 每页数量
|
// - pageSize (可选): 每页数量
|
||||||
// 返回数据格式: ApiResponse<List<WorkItem>>
|
// 返回数据格式: ApiResponse<List<WorkItem>>
|
||||||
// 标签页顺序:0-作品, 1-收藏, 2-赞过
|
// 标签页顺序:0-作品, 1-收藏, 2-赞过
|
||||||
binding.tabWorks.setVisibility(index == 0 ? View.VISIBLE : View.GONE);
|
binding.tabWorksContent.setVisibility(index == 0 ? View.VISIBLE : View.GONE);
|
||||||
binding.tabFavorites.setVisibility(index == 1 ? View.VISIBLE : View.GONE);
|
binding.tabFavorites.setVisibility(index == 1 ? View.VISIBLE : View.GONE);
|
||||||
binding.tabLiked.setVisibility(index == 2 ? View.VISIBLE : View.GONE);
|
binding.tabLikedContent.setVisibility(index == 2 ? View.VISIBLE : View.GONE);
|
||||||
|
|
||||||
// 当切换到作品标签页时,重新加载作品列表
|
// 当切换到作品标签页时,重新加载作品列表
|
||||||
if (index == 0) {
|
if (index == 0) {
|
||||||
|
|
@ -1030,11 +1162,175 @@ public class ProfileActivity extends AppCompatActivity {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// 加载收藏数(点赞的直播间数量)
|
// 加载点赞的直播间数量
|
||||||
loadLikedRoomsCount();
|
loadLikedRoomsCount();
|
||||||
|
|
||||||
// 加载好友数量
|
// 加载好友数量
|
||||||
loadFriendsCount();
|
loadFriendsCount();
|
||||||
|
|
||||||
|
// 加载收藏数量
|
||||||
|
loadCollectionsCount();
|
||||||
|
|
||||||
|
// 加载获赞数量(作品点赞总数)
|
||||||
|
loadTotalLikesCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加载收藏数(点赞的直播间数量)
|
||||||
|
*/
|
||||||
|
private void loadLikedRoomsCount() {
|
||||||
|
com.example.livestreaming.net.ApiService apiService =
|
||||||
|
com.example.livestreaming.net.ApiClient.getService(this);
|
||||||
|
retrofit2.Call<com.example.livestreaming.net.ApiResponse<com.example.livestreaming.net.PageResponse<java.util.Map<String, Object>>>> call =
|
||||||
|
apiService.getMyLikedRooms(1, 1); // 只获取第一页,用于获取总数
|
||||||
|
|
||||||
|
call.enqueue(new retrofit2.Callback<com.example.livestreaming.net.ApiResponse<com.example.livestreaming.net.PageResponse<java.util.Map<String, Object>>>>() {
|
||||||
|
@Override
|
||||||
|
public void onResponse(retrofit2.Call<com.example.livestreaming.net.ApiResponse<com.example.livestreaming.net.PageResponse<java.util.Map<String, Object>>>> call,
|
||||||
|
retrofit2.Response<com.example.livestreaming.net.ApiResponse<com.example.livestreaming.net.PageResponse<java.util.Map<String, Object>>>> response) {
|
||||||
|
if (response.isSuccessful() && response.body() != null) {
|
||||||
|
com.example.livestreaming.net.ApiResponse<com.example.livestreaming.net.PageResponse<java.util.Map<String, Object>>> apiResponse = response.body();
|
||||||
|
if (apiResponse.getCode() == 200 && apiResponse.getData() != null) {
|
||||||
|
com.example.livestreaming.net.PageResponse<java.util.Map<String, Object>> pageData = apiResponse.getData();
|
||||||
|
Long total = pageData.getTotal();
|
||||||
|
// 保存点赞数量供其他地方使用
|
||||||
|
likedRoomsTotal = total != null ? total : 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(retrofit2.Call<com.example.livestreaming.net.ApiResponse<com.example.livestreaming.net.PageResponse<java.util.Map<String, Object>>>> call, Throwable t) {
|
||||||
|
// 忽略错误,使用默认显示
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存点赞直播间数量
|
||||||
|
private long likedRoomsTotal = 0;
|
||||||
|
|
||||||
|
// 保存收藏数量
|
||||||
|
private long collectedWorksCount = 0;
|
||||||
|
private long collectedRoomsCount = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加载收藏数量(作品+直播间)
|
||||||
|
*/
|
||||||
|
private void loadCollectionsCount() {
|
||||||
|
if (!AuthHelper.isLoggedIn(this)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 重置计数
|
||||||
|
collectedWorksCount = 0;
|
||||||
|
collectedRoomsCount = 0;
|
||||||
|
|
||||||
|
// 加载收藏的作品数量
|
||||||
|
ApiClient.getService(this).getMyCollectedWorks(1, 1)
|
||||||
|
.enqueue(new Callback<ApiResponse<PageResponse<WorksResponse>>>() {
|
||||||
|
@Override
|
||||||
|
public void onResponse(Call<ApiResponse<PageResponse<WorksResponse>>> call,
|
||||||
|
Response<ApiResponse<PageResponse<WorksResponse>>> response) {
|
||||||
|
if (response.isSuccessful() && response.body() != null && response.body().isOk()) {
|
||||||
|
PageResponse<WorksResponse> pageData = response.body().getData();
|
||||||
|
if (pageData != null) {
|
||||||
|
Long total = pageData.getTotal();
|
||||||
|
collectedWorksCount = total != null ? total : 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 更新总收藏数量显示
|
||||||
|
updateCollectionsCountDisplay();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Call<ApiResponse<PageResponse<WorksResponse>>> call, Throwable t) {
|
||||||
|
Log.e(TAG, "加载收藏作品数量失败: " + t.getMessage());
|
||||||
|
updateCollectionsCountDisplay();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 加载收藏的直播间数量(使用点赞的直播间作为收藏)
|
||||||
|
ApiClient.getService(this).getMyLikedRooms(1, 1)
|
||||||
|
.enqueue(new Callback<ApiResponse<PageResponse<java.util.Map<String, Object>>>>() {
|
||||||
|
@Override
|
||||||
|
public void onResponse(Call<ApiResponse<PageResponse<java.util.Map<String, Object>>>> call,
|
||||||
|
Response<ApiResponse<PageResponse<java.util.Map<String, Object>>>> response) {
|
||||||
|
if (response.isSuccessful() && response.body() != null && response.body().isOk()) {
|
||||||
|
PageResponse<java.util.Map<String, Object>> pageData = response.body().getData();
|
||||||
|
if (pageData != null) {
|
||||||
|
Long total = pageData.getTotal();
|
||||||
|
collectedRoomsCount = total != null ? total : 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 更新总收藏数量显示
|
||||||
|
updateCollectionsCountDisplay();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Call<ApiResponse<PageResponse<java.util.Map<String, Object>>>> call, Throwable t) {
|
||||||
|
Log.e(TAG, "加载收藏直播间数量失败: " + t.getMessage());
|
||||||
|
updateCollectionsCountDisplay();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新收藏数量显示
|
||||||
|
*/
|
||||||
|
private void updateCollectionsCountDisplay() {
|
||||||
|
long totalCount = collectedWorksCount + collectedRoomsCount;
|
||||||
|
if (binding.collectionsCount != null) {
|
||||||
|
binding.collectionsCount.setText(totalCount + "个");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加载获赞数量(统计所有作品的点赞总数)
|
||||||
|
*/
|
||||||
|
private void loadTotalLikesCount() {
|
||||||
|
if (!AuthHelper.isLoggedIn(this)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取当前用户ID
|
||||||
|
String userIdStr = com.example.livestreaming.net.AuthStore.getUserId(this);
|
||||||
|
if (userIdStr == null || userIdStr.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int userId;
|
||||||
|
try {
|
||||||
|
userId = Integer.parseInt(userIdStr);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取用户的所有作品,然后统计点赞总数
|
||||||
|
ApiClient.getService(this).getUserWorks(userId, 1, 100)
|
||||||
|
.enqueue(new Callback<ApiResponse<PageResponse<WorksResponse>>>() {
|
||||||
|
@Override
|
||||||
|
public void onResponse(Call<ApiResponse<PageResponse<WorksResponse>>> call,
|
||||||
|
Response<ApiResponse<PageResponse<WorksResponse>>> response) {
|
||||||
|
if (response.isSuccessful() && response.body() != null && response.body().isOk()) {
|
||||||
|
PageResponse<WorksResponse> pageData = response.body().getData();
|
||||||
|
if (pageData != null && pageData.getList() != null) {
|
||||||
|
long totalLikes = 0;
|
||||||
|
for (WorksResponse work : pageData.getList()) {
|
||||||
|
if (work.getLikeCount() != null) {
|
||||||
|
totalLikes += work.getLikeCount();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 更新获赞数量显示
|
||||||
|
binding.likes.setText(totalLikes + "\n获赞");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Call<ApiResponse<PageResponse<WorksResponse>>> call, Throwable t) {
|
||||||
|
Log.e(TAG, "加载获赞数量失败: " + t.getMessage());
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -1089,41 +1385,6 @@ public class ProfileActivity extends AppCompatActivity {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 加载收藏数(点赞的直播间数量)
|
|
||||||
*/
|
|
||||||
private void loadLikedRoomsCount() {
|
|
||||||
com.example.livestreaming.net.ApiService apiService =
|
|
||||||
com.example.livestreaming.net.ApiClient.getService(this);
|
|
||||||
retrofit2.Call<com.example.livestreaming.net.ApiResponse<com.example.livestreaming.net.PageResponse<java.util.Map<String, Object>>>> call =
|
|
||||||
apiService.getMyLikedRooms(1, 1); // 只获取第一页,用于获取总数
|
|
||||||
|
|
||||||
call.enqueue(new retrofit2.Callback<com.example.livestreaming.net.ApiResponse<com.example.livestreaming.net.PageResponse<java.util.Map<String, Object>>>>() {
|
|
||||||
@Override
|
|
||||||
public void onResponse(retrofit2.Call<com.example.livestreaming.net.ApiResponse<com.example.livestreaming.net.PageResponse<java.util.Map<String, Object>>>> call,
|
|
||||||
retrofit2.Response<com.example.livestreaming.net.ApiResponse<com.example.livestreaming.net.PageResponse<java.util.Map<String, Object>>>> response) {
|
|
||||||
if (response.isSuccessful() && response.body() != null) {
|
|
||||||
com.example.livestreaming.net.ApiResponse<com.example.livestreaming.net.PageResponse<java.util.Map<String, Object>>> apiResponse = response.body();
|
|
||||||
if (apiResponse.getCode() == 200 && apiResponse.getData() != null) {
|
|
||||||
com.example.livestreaming.net.PageResponse<java.util.Map<String, Object>> pageData = apiResponse.getData();
|
|
||||||
Long total = pageData.getTotal();
|
|
||||||
|
|
||||||
// 更新快捷操作区域的收藏数
|
|
||||||
android.widget.TextView likedRoomsCountText = findViewById(R.id.likedRoomsCount);
|
|
||||||
if (likedRoomsCountText != null) {
|
|
||||||
likedRoomsCountText.setText((total != null ? total : 0) + "个直播间");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onFailure(retrofit2.Call<com.example.livestreaming.net.ApiResponse<com.example.livestreaming.net.PageResponse<java.util.Map<String, Object>>>> call, Throwable t) {
|
|
||||||
// 忽略错误,使用默认显示
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 加载钱包余额
|
* 加载钱包余额
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -123,7 +123,7 @@ public class ProfileWebViewActivity extends AppCompatActivity {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (id == R.id.nav_wish_tree) {
|
if (id == R.id.nav_wish_tree) {
|
||||||
WishTreeWebViewActivity.start(this);
|
WishTreeActivity.start(this);
|
||||||
finish();
|
finish();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,378 @@
|
||||||
|
package com.example.livestreaming;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.ClipData;
|
||||||
|
import android.content.ClipboardManager;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.ArrayAdapter;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import androidx.activity.result.ActivityResultLauncher;
|
||||||
|
import androidx.activity.result.contract.ActivityResultContracts;
|
||||||
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
|
|
||||||
|
import com.bumptech.glide.Glide;
|
||||||
|
import com.example.livestreaming.databinding.ActivityPublishCenterBinding;
|
||||||
|
import com.example.livestreaming.net.ApiClient;
|
||||||
|
import com.example.livestreaming.net.ApiResponse;
|
||||||
|
import com.example.livestreaming.net.CategoryResponse;
|
||||||
|
import com.example.livestreaming.net.CreateRoomRequest;
|
||||||
|
import com.example.livestreaming.net.FileUploadResponse;
|
||||||
|
import com.example.livestreaming.net.Room;
|
||||||
|
import com.example.livestreaming.net.StreamUrls;
|
||||||
|
import com.example.livestreaming.net.WorksRequest;
|
||||||
|
import com.google.android.material.tabs.TabLayout;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import okhttp3.MediaType;
|
||||||
|
import okhttp3.MultipartBody;
|
||||||
|
import okhttp3.RequestBody;
|
||||||
|
import retrofit2.Call;
|
||||||
|
import retrofit2.Callback;
|
||||||
|
import retrofit2.Response;
|
||||||
|
|
||||||
|
public class PublishCenterActivity extends AppCompatActivity {
|
||||||
|
|
||||||
|
private ActivityPublishCenterBinding binding;
|
||||||
|
private int currentTab = 0;
|
||||||
|
private List<CategoryResponse> categoryList = new ArrayList<>();
|
||||||
|
private int selectedCategoryId = -1;
|
||||||
|
private Uri dynamicCoverUri = null;
|
||||||
|
private ActivityResultLauncher<Intent> imagePickerLauncher;
|
||||||
|
|
||||||
|
public static void start(Context context) {
|
||||||
|
context.startActivity(new Intent(context, PublishCenterActivity.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
if (!AuthHelper.requireLogin(this, "发布内容需要登录")) {
|
||||||
|
finish();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
binding = ActivityPublishCenterBinding.inflate(getLayoutInflater());
|
||||||
|
setContentView(binding.getRoot());
|
||||||
|
setupImagePicker();
|
||||||
|
setupToolbar();
|
||||||
|
setupTabs();
|
||||||
|
setupClickListeners();
|
||||||
|
loadCategories();
|
||||||
|
showTab(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupImagePicker() {
|
||||||
|
imagePickerLauncher = registerForActivityResult(
|
||||||
|
new ActivityResultContracts.StartActivityForResult(),
|
||||||
|
result -> {
|
||||||
|
if (result.getResultCode() == Activity.RESULT_OK && result.getData() != null) {
|
||||||
|
Uri uri = result.getData().getData();
|
||||||
|
if (uri != null) {
|
||||||
|
dynamicCoverUri = uri;
|
||||||
|
showDynamicCover(uri);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupToolbar() {
|
||||||
|
binding.btnBack.setOnClickListener(v -> finish());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupTabs() {
|
||||||
|
binding.tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
|
||||||
|
@Override
|
||||||
|
public void onTabSelected(TabLayout.Tab tab) { showTab(tab.getPosition()); }
|
||||||
|
@Override
|
||||||
|
public void onTabUnselected(TabLayout.Tab tab) {}
|
||||||
|
@Override
|
||||||
|
public void onTabReselected(TabLayout.Tab tab) {}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupClickListeners() {
|
||||||
|
binding.btnStartLive.setOnClickListener(v -> startMobileLive());
|
||||||
|
binding.btnPublishDynamic.setOnClickListener(v -> publishDynamic());
|
||||||
|
binding.dynamicCoverContainer.setOnClickListener(v -> pickDynamicCover());
|
||||||
|
binding.btnRemoveDynamicCover.setOnClickListener(v -> removeDynamicCover());
|
||||||
|
binding.btnPublishWork.setOnClickListener(v -> PublishWorkActivity.start(this));
|
||||||
|
binding.btnCopyStreamUrl.setOnClickListener(v -> copyToClipboard("推流地址", binding.tvStreamUrl.getText().toString()));
|
||||||
|
binding.btnCopyStreamKey.setOnClickListener(v -> copyToClipboard("推流码", binding.tvStreamKey.getText().toString()));
|
||||||
|
binding.btnGetStreamInfo.setOnClickListener(v -> createPcLiveRoom());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showTab(int position) {
|
||||||
|
currentTab = position;
|
||||||
|
binding.contentMobileLive.setVisibility(View.GONE);
|
||||||
|
binding.contentDynamic.setVisibility(View.GONE);
|
||||||
|
binding.contentWork.setVisibility(View.GONE);
|
||||||
|
binding.contentPcLive.setVisibility(View.GONE);
|
||||||
|
switch (position) {
|
||||||
|
case 0: binding.contentMobileLive.setVisibility(View.VISIBLE); break;
|
||||||
|
case 1: binding.contentDynamic.setVisibility(View.VISIBLE); break;
|
||||||
|
case 2: binding.contentWork.setVisibility(View.VISIBLE); break;
|
||||||
|
case 3: binding.contentPcLive.setVisibility(View.VISIBLE); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadCategories() {
|
||||||
|
ApiClient.getService(this).getLiveRoomCategories().enqueue(new Callback<ApiResponse<List<CategoryResponse>>>() {
|
||||||
|
@Override
|
||||||
|
public void onResponse(Call<ApiResponse<List<CategoryResponse>>> call, Response<ApiResponse<List<CategoryResponse>>> response) {
|
||||||
|
if (response.isSuccessful() && response.body() != null && response.body().isOk()) {
|
||||||
|
categoryList = response.body().getData();
|
||||||
|
if (categoryList == null) categoryList = new ArrayList<>();
|
||||||
|
}
|
||||||
|
setupCategorySpinner();
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void onFailure(Call<ApiResponse<List<CategoryResponse>>> call, Throwable t) {
|
||||||
|
setupCategorySpinner();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupCategorySpinner() {
|
||||||
|
List<String> names = new ArrayList<>();
|
||||||
|
names.add("请选择分类");
|
||||||
|
for (CategoryResponse cat : categoryList) names.add(cat.getName());
|
||||||
|
ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item, names);
|
||||||
|
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
||||||
|
binding.spinnerPcCategory.setAdapter(adapter);
|
||||||
|
binding.spinnerPcCategory.setOnItemSelectedListener(new android.widget.AdapterView.OnItemSelectedListener() {
|
||||||
|
@Override
|
||||||
|
public void onItemSelected(android.widget.AdapterView<?> parent, View view, int pos, long id) {
|
||||||
|
selectedCategoryId = (pos > 0 && pos <= categoryList.size()) ? categoryList.get(pos - 1).getId() : -1;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void onNothingSelected(android.widget.AdapterView<?> parent) { selectedCategoryId = -1; }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void startMobileLive() {
|
||||||
|
String title = binding.etLiveTitle.getText().toString().trim();
|
||||||
|
if (TextUtils.isEmpty(title)) title = "我的直播间";
|
||||||
|
Intent intent = new Intent(this, BroadcastActivity.class);
|
||||||
|
intent.putExtra("title", title);
|
||||||
|
startActivity(intent);
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void pickDynamicCover() {
|
||||||
|
Intent intent = new Intent(Intent.ACTION_PICK);
|
||||||
|
intent.setType("image/*");
|
||||||
|
imagePickerLauncher.launch(intent);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showDynamicCover(Uri uri) {
|
||||||
|
binding.ivDynamicCover.setVisibility(View.VISIBLE);
|
||||||
|
binding.dynamicCoverPlaceholder.setVisibility(View.GONE);
|
||||||
|
binding.btnRemoveDynamicCover.setVisibility(View.VISIBLE);
|
||||||
|
Glide.with(this).load(uri).centerCrop().into(binding.ivDynamicCover);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void removeDynamicCover() {
|
||||||
|
dynamicCoverUri = null;
|
||||||
|
binding.ivDynamicCover.setVisibility(View.GONE);
|
||||||
|
binding.dynamicCoverPlaceholder.setVisibility(View.VISIBLE);
|
||||||
|
binding.btnRemoveDynamicCover.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void publishDynamic() {
|
||||||
|
String content = binding.etDynamicContent.getText().toString().trim();
|
||||||
|
if (TextUtils.isEmpty(content)) {
|
||||||
|
Toast.makeText(this, "请输入动态内容", Toast.LENGTH_SHORT).show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (content.length() > 1000) {
|
||||||
|
Toast.makeText(this, "内容不能超过1000字", Toast.LENGTH_SHORT).show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
binding.btnPublishDynamic.setEnabled(false);
|
||||||
|
binding.btnPublishDynamic.setText("发布中...");
|
||||||
|
|
||||||
|
if (dynamicCoverUri != null) {
|
||||||
|
// 用户选择了封面,上传后发布
|
||||||
|
uploadDynamicCoverAndPublish(content);
|
||||||
|
} else {
|
||||||
|
// 用户没选封面,使用特殊标记(纯文字动态)
|
||||||
|
// 使用 "text_only" 作为标记,在展示时识别为纯文字动态
|
||||||
|
doPublishDynamic(content, "text_only");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void uploadDynamicCoverAndPublish(String content) {
|
||||||
|
try {
|
||||||
|
File file = uriToFile(dynamicCoverUri);
|
||||||
|
if (file == null) {
|
||||||
|
Toast.makeText(this, "无法读取图片", Toast.LENGTH_SHORT).show();
|
||||||
|
resetDynamicButton();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
RequestBody requestFile = RequestBody.create(MediaType.parse("image/*"), file);
|
||||||
|
MultipartBody.Part body = MultipartBody.Part.createFormData("file", file.getName(), requestFile);
|
||||||
|
RequestBody model = RequestBody.create(MediaType.parse("text/plain"), "work");
|
||||||
|
RequestBody pid = RequestBody.create(MediaType.parse("text/plain"), "0");
|
||||||
|
ApiClient.getService(this).uploadImage(body, model, pid).enqueue(new Callback<ApiResponse<FileUploadResponse>>() {
|
||||||
|
@Override
|
||||||
|
public void onResponse(Call<ApiResponse<FileUploadResponse>> call, Response<ApiResponse<FileUploadResponse>> response) {
|
||||||
|
if (response.isSuccessful() && response.body() != null && response.body().isOk()) {
|
||||||
|
FileUploadResponse data = response.body().getData();
|
||||||
|
doPublishDynamic(content, data != null ? data.getUrl() : null);
|
||||||
|
} else {
|
||||||
|
resetDynamicButton();
|
||||||
|
Toast.makeText(PublishCenterActivity.this, "封面上传失败", Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void onFailure(Call<ApiResponse<FileUploadResponse>> call, Throwable t) {
|
||||||
|
resetDynamicButton();
|
||||||
|
Toast.makeText(PublishCenterActivity.this, "网络错误", Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (Exception e) {
|
||||||
|
resetDynamicButton();
|
||||||
|
Toast.makeText(this, "图片处理失败", Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doPublishDynamic(String content, String coverUrl) {
|
||||||
|
WorksRequest request = new WorksRequest();
|
||||||
|
request.setTitle("");
|
||||||
|
request.setDescription(content);
|
||||||
|
request.setType("IMAGE");
|
||||||
|
request.setImageUrls(new ArrayList<>());
|
||||||
|
// 如果没有封面,设置特殊标识URL,表示这是纯文字动态
|
||||||
|
if (coverUrl == null || coverUrl.isEmpty()) {
|
||||||
|
request.setCoverUrl("TEXT_ONLY_DYNAMIC_PLACEHOLDER");
|
||||||
|
} else {
|
||||||
|
request.setCoverUrl(coverUrl);
|
||||||
|
}
|
||||||
|
ApiClient.getService(this).publishWork(request).enqueue(new Callback<ApiResponse<Long>>() {
|
||||||
|
@Override
|
||||||
|
public void onResponse(Call<ApiResponse<Long>> call, Response<ApiResponse<Long>> response) {
|
||||||
|
resetDynamicButton();
|
||||||
|
if (response.isSuccessful() && response.body() != null && response.body().isOk()) {
|
||||||
|
Toast.makeText(PublishCenterActivity.this, "动态发布成功", Toast.LENGTH_SHORT).show();
|
||||||
|
binding.etDynamicContent.setText("");
|
||||||
|
removeDynamicCover();
|
||||||
|
finish();
|
||||||
|
} else {
|
||||||
|
String msg = response.body() != null ? response.body().getMessage() : "发布失败";
|
||||||
|
Toast.makeText(PublishCenterActivity.this, msg, Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void onFailure(Call<ApiResponse<Long>> call, Throwable t) {
|
||||||
|
resetDynamicButton();
|
||||||
|
Toast.makeText(PublishCenterActivity.this, "网络错误", Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void resetDynamicButton() {
|
||||||
|
binding.btnPublishDynamic.setEnabled(true);
|
||||||
|
binding.btnPublishDynamic.setText("发布动态");
|
||||||
|
}
|
||||||
|
|
||||||
|
private File uriToFile(Uri uri) {
|
||||||
|
try {
|
||||||
|
InputStream is = getContentResolver().openInputStream(uri);
|
||||||
|
if (is == null) return null;
|
||||||
|
File file = new File(getCacheDir(), "temp_cover_" + System.currentTimeMillis() + ".jpg");
|
||||||
|
FileOutputStream os = new FileOutputStream(file);
|
||||||
|
byte[] buf = new byte[4096];
|
||||||
|
int len;
|
||||||
|
while ((len = is.read(buf)) != -1) os.write(buf, 0, len);
|
||||||
|
is.close();
|
||||||
|
os.close();
|
||||||
|
return file;
|
||||||
|
} catch (Exception e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createPcLiveRoom() {
|
||||||
|
String title = binding.etPcLiveTitle.getText().toString().trim();
|
||||||
|
if (TextUtils.isEmpty(title)) {
|
||||||
|
Toast.makeText(this, "请输入直播标题", Toast.LENGTH_SHORT).show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (selectedCategoryId <= 0) {
|
||||||
|
Toast.makeText(this, "请选择直播分类", Toast.LENGTH_SHORT).show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
binding.btnGetStreamInfo.setEnabled(false);
|
||||||
|
binding.btnGetStreamInfo.setText("创建中...");
|
||||||
|
binding.streamInfoLoading.setVisibility(View.VISIBLE);
|
||||||
|
|
||||||
|
// 获取当前用户昵称作为主播名称
|
||||||
|
String streamerName = com.example.livestreaming.net.AuthStore.getNickname(this);
|
||||||
|
if (TextUtils.isEmpty(streamerName)) {
|
||||||
|
streamerName = title; // 如果没有昵称,使用标题
|
||||||
|
}
|
||||||
|
|
||||||
|
CreateRoomRequest request = new CreateRoomRequest(title, streamerName, "pc");
|
||||||
|
request.setCategoryId(selectedCategoryId);
|
||||||
|
|
||||||
|
ApiClient.getService(this).createRoom(request).enqueue(new Callback<ApiResponse<Room>>() {
|
||||||
|
@Override
|
||||||
|
public void onResponse(Call<ApiResponse<Room>> call, Response<ApiResponse<Room>> response) {
|
||||||
|
binding.btnGetStreamInfo.setEnabled(true);
|
||||||
|
binding.btnGetStreamInfo.setText("创建直播间并获取推流信息");
|
||||||
|
binding.streamInfoLoading.setVisibility(View.GONE);
|
||||||
|
if (response.isSuccessful() && response.body() != null && response.body().isOk()) {
|
||||||
|
Room room = response.body().getData();
|
||||||
|
if (room != null) {
|
||||||
|
showStreamInfo(room);
|
||||||
|
} else {
|
||||||
|
Toast.makeText(PublishCenterActivity.this, "创建成功但未获取到推流信息", Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
String msg = response.body() != null ? response.body().getMessage() : "创建直播间失败";
|
||||||
|
Toast.makeText(PublishCenterActivity.this, msg, Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void onFailure(Call<ApiResponse<Room>> call, Throwable t) {
|
||||||
|
binding.btnGetStreamInfo.setEnabled(true);
|
||||||
|
binding.btnGetStreamInfo.setText("创建直播间并获取推流信息");
|
||||||
|
binding.streamInfoLoading.setVisibility(View.GONE);
|
||||||
|
Toast.makeText(PublishCenterActivity.this, "网络错误", Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showStreamInfo(Room room) {
|
||||||
|
binding.streamInfoContent.setVisibility(View.VISIBLE);
|
||||||
|
String streamKey = room.getStreamKey();
|
||||||
|
StreamUrls streamUrls = room.getStreamUrls();
|
||||||
|
String pushUrl = (streamUrls != null && streamUrls.getRtmp() != null) ? streamUrls.getRtmp() : "";
|
||||||
|
binding.tvStreamUrl.setText(!TextUtils.isEmpty(pushUrl) ? pushUrl : "未获取到推流地址");
|
||||||
|
binding.tvStreamKey.setText(!TextUtils.isEmpty(streamKey) ? streamKey : "未获取到推流码");
|
||||||
|
Toast.makeText(this, "直播间创建成功!", Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void copyToClipboard(String label, String text) {
|
||||||
|
if (TextUtils.isEmpty(text) || text.startsWith("未获取")) {
|
||||||
|
Toast.makeText(this, "内容为空", Toast.LENGTH_SHORT).show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ClipboardManager clipboard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
|
||||||
|
if (clipboard != null) {
|
||||||
|
clipboard.setPrimaryClip(ClipData.newPlainText(label, text));
|
||||||
|
Toast.makeText(this, label + "已复制", Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -56,7 +56,7 @@ public class TableGamesActivity extends BaseCategoryActivity {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (id == R.id.nav_wish_tree) {
|
if (id == R.id.nav_wish_tree) {
|
||||||
WishTreeWebViewActivity.start(this);
|
WishTreeActivity.start(this);
|
||||||
finish();
|
finish();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -211,7 +211,7 @@ public class VoiceMatchActivity extends AppCompatActivity {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (id == R.id.nav_wish_tree) {
|
if (id == R.id.nav_wish_tree) {
|
||||||
WishTreeWebViewActivity.start(this);
|
WishTreeActivity.start(this);
|
||||||
finish();
|
finish();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,313 @@
|
||||||
|
package com.example.livestreaming;
|
||||||
|
|
||||||
|
import android.animation.AnimatorSet;
|
||||||
|
import android.animation.ObjectAnimator;
|
||||||
|
import android.animation.ValueAnimator;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.animation.AccelerateDecelerateInterpolator;
|
||||||
|
import android.view.animation.DecelerateInterpolator;
|
||||||
|
import android.view.animation.OvershootInterpolator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 许愿牌动画工具类
|
||||||
|
* 实现心愿从底部飘到树上的动画效果
|
||||||
|
*/
|
||||||
|
public class WishTagAnimator {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 执行心愿飘到树上的动画
|
||||||
|
* @param wishTag 许愿牌View
|
||||||
|
* @param startX 起始X坐标
|
||||||
|
* @param startY 起始Y坐标
|
||||||
|
* @param targetX 目标X坐标
|
||||||
|
* @param targetY 目标Y坐标
|
||||||
|
* @param duration 动画时长(毫秒)
|
||||||
|
* @param onComplete 动画完成回调
|
||||||
|
*/
|
||||||
|
public static void animateWishToTree(View wishTag, float startX, float startY,
|
||||||
|
float targetX, float targetY, long duration,
|
||||||
|
Runnable onComplete) {
|
||||||
|
// 设置初始位置和状态
|
||||||
|
wishTag.setX(startX);
|
||||||
|
wishTag.setY(startY);
|
||||||
|
wishTag.setAlpha(0f);
|
||||||
|
wishTag.setScaleX(0.3f);
|
||||||
|
wishTag.setScaleY(0.3f);
|
||||||
|
wishTag.setRotation(0f);
|
||||||
|
wishTag.setVisibility(View.VISIBLE);
|
||||||
|
|
||||||
|
// 创建动画集合
|
||||||
|
AnimatorSet animatorSet = new AnimatorSet();
|
||||||
|
|
||||||
|
// X轴移动动画
|
||||||
|
ObjectAnimator moveX = ObjectAnimator.ofFloat(wishTag, "x", startX, targetX);
|
||||||
|
moveX.setDuration(duration);
|
||||||
|
moveX.setInterpolator(new DecelerateInterpolator(1.5f));
|
||||||
|
|
||||||
|
// Y轴移动动画(带轻微弹跳)
|
||||||
|
ObjectAnimator moveY = ObjectAnimator.ofFloat(wishTag, "y", startY, targetY);
|
||||||
|
moveY.setDuration(duration);
|
||||||
|
moveY.setInterpolator(new DecelerateInterpolator(2f));
|
||||||
|
|
||||||
|
// 淡入动画
|
||||||
|
ObjectAnimator fadeIn = ObjectAnimator.ofFloat(wishTag, "alpha", 0f, 1f);
|
||||||
|
fadeIn.setDuration(duration / 3);
|
||||||
|
|
||||||
|
// 缩放动画
|
||||||
|
ObjectAnimator scaleX = ObjectAnimator.ofFloat(wishTag, "scaleX", 0.3f, 1.1f, 1f);
|
||||||
|
scaleX.setDuration(duration);
|
||||||
|
scaleX.setInterpolator(new OvershootInterpolator(1.2f));
|
||||||
|
|
||||||
|
ObjectAnimator scaleY = ObjectAnimator.ofFloat(wishTag, "scaleY", 0.3f, 1.1f, 1f);
|
||||||
|
scaleY.setDuration(duration);
|
||||||
|
scaleY.setInterpolator(new OvershootInterpolator(1.2f));
|
||||||
|
|
||||||
|
// 轻微旋转摇摆动画
|
||||||
|
ObjectAnimator rotate = ObjectAnimator.ofFloat(wishTag, "rotation", 0f, -8f, 8f, -5f, 5f, -2f, 2f, 0f);
|
||||||
|
rotate.setDuration(duration + 500);
|
||||||
|
rotate.setInterpolator(new DecelerateInterpolator());
|
||||||
|
|
||||||
|
// 同时播放所有动画
|
||||||
|
animatorSet.playTogether(moveX, moveY, fadeIn, scaleX, scaleY, rotate);
|
||||||
|
|
||||||
|
// 动画完成后的回调
|
||||||
|
if (onComplete != null) {
|
||||||
|
animatorSet.addListener(new android.animation.AnimatorListenerAdapter() {
|
||||||
|
@Override
|
||||||
|
public void onAnimationEnd(android.animation.Animator animation) {
|
||||||
|
// 添加持续的轻微摇摆效果
|
||||||
|
startSwingAnimation(wishTag);
|
||||||
|
onComplete.run();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
animatorSet.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 简化版动画 - 从屏幕底部中央飘到目标位置
|
||||||
|
*/
|
||||||
|
public static void animateFromBottom(View wishTag, View parentView, float targetX, float targetY,
|
||||||
|
Runnable onComplete) {
|
||||||
|
float startX = parentView.getWidth() / 2f - wishTag.getWidth() / 2f;
|
||||||
|
float startY = parentView.getHeight();
|
||||||
|
|
||||||
|
animateWishToTree(wishTag, startX, startY, targetX, targetY, 1500, onComplete);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 持续的轻微摇摆动画(模拟风吹效果)
|
||||||
|
*/
|
||||||
|
public static void startSwingAnimation(View wishTag) {
|
||||||
|
ObjectAnimator swing = ObjectAnimator.ofFloat(wishTag, "rotation", -2f, 2f);
|
||||||
|
swing.setDuration(2000);
|
||||||
|
swing.setRepeatCount(ValueAnimator.INFINITE);
|
||||||
|
swing.setRepeatMode(ValueAnimator.REVERSE);
|
||||||
|
swing.setInterpolator(new AccelerateDecelerateInterpolator());
|
||||||
|
swing.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 心愿牌出现动画(淡入+缩放)
|
||||||
|
*/
|
||||||
|
public static void animateAppear(View wishTag, long delay) {
|
||||||
|
wishTag.setAlpha(0f);
|
||||||
|
wishTag.setScaleX(0.5f);
|
||||||
|
wishTag.setScaleY(0.5f);
|
||||||
|
wishTag.setVisibility(View.VISIBLE);
|
||||||
|
|
||||||
|
AnimatorSet animatorSet = new AnimatorSet();
|
||||||
|
|
||||||
|
ObjectAnimator fadeIn = ObjectAnimator.ofFloat(wishTag, "alpha", 0f, 1f);
|
||||||
|
fadeIn.setDuration(500);
|
||||||
|
|
||||||
|
ObjectAnimator scaleX = ObjectAnimator.ofFloat(wishTag, "scaleX", 0.5f, 1f);
|
||||||
|
scaleX.setDuration(500);
|
||||||
|
|
||||||
|
ObjectAnimator scaleY = ObjectAnimator.ofFloat(wishTag, "scaleY", 0.5f, 1f);
|
||||||
|
scaleY.setDuration(500);
|
||||||
|
|
||||||
|
animatorSet.playTogether(fadeIn, scaleX, scaleY);
|
||||||
|
animatorSet.setStartDelay(delay);
|
||||||
|
animatorSet.setInterpolator(new OvershootInterpolator(1.5f));
|
||||||
|
animatorSet.start();
|
||||||
|
|
||||||
|
// 出现后开始摇摆
|
||||||
|
wishTag.postDelayed(() -> startSwingAnimation(wishTag), delay + 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 心愿牌消失动画
|
||||||
|
*/
|
||||||
|
public static void animateDisappear(View wishTag, Runnable onComplete) {
|
||||||
|
AnimatorSet animatorSet = new AnimatorSet();
|
||||||
|
|
||||||
|
ObjectAnimator fadeOut = ObjectAnimator.ofFloat(wishTag, "alpha", 1f, 0f);
|
||||||
|
fadeOut.setDuration(300);
|
||||||
|
|
||||||
|
ObjectAnimator scaleX = ObjectAnimator.ofFloat(wishTag, "scaleX", 1f, 0.3f);
|
||||||
|
scaleX.setDuration(300);
|
||||||
|
|
||||||
|
ObjectAnimator scaleY = ObjectAnimator.ofFloat(wishTag, "scaleY", 1f, 0.3f);
|
||||||
|
scaleY.setDuration(300);
|
||||||
|
|
||||||
|
animatorSet.playTogether(fadeOut, scaleX, scaleY);
|
||||||
|
|
||||||
|
if (onComplete != null) {
|
||||||
|
animatorSet.addListener(new android.animation.AnimatorListenerAdapter() {
|
||||||
|
@Override
|
||||||
|
public void onAnimationEnd(android.animation.Animator animation) {
|
||||||
|
wishTag.setVisibility(View.GONE);
|
||||||
|
onComplete.run();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
animatorSet.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 渐隐旧心愿并渐显新心愿的替换动画
|
||||||
|
* @param wishTag 心愿牌View
|
||||||
|
* @param newText 新心愿文字
|
||||||
|
* @param newBackground 新心愿背景资源
|
||||||
|
* @param onComplete 动画完成回调
|
||||||
|
*/
|
||||||
|
public static void animateFadeOutAndReplace(android.widget.TextView wishTag, String newText,
|
||||||
|
int newBackground, Runnable onComplete) {
|
||||||
|
// 第一阶段:旧心愿渐隐
|
||||||
|
ObjectAnimator fadeOut = ObjectAnimator.ofFloat(wishTag, "alpha", 1f, 0f);
|
||||||
|
fadeOut.setDuration(600);
|
||||||
|
fadeOut.setInterpolator(new AccelerateDecelerateInterpolator());
|
||||||
|
|
||||||
|
fadeOut.addListener(new android.animation.AnimatorListenerAdapter() {
|
||||||
|
@Override
|
||||||
|
public void onAnimationEnd(android.animation.Animator animation) {
|
||||||
|
// 更新内容
|
||||||
|
wishTag.setText(newText);
|
||||||
|
wishTag.setBackgroundResource(newBackground);
|
||||||
|
|
||||||
|
// 第二阶段:新心愿渐显
|
||||||
|
ObjectAnimator fadeIn = ObjectAnimator.ofFloat(wishTag, "alpha", 0f, 1f);
|
||||||
|
fadeIn.setDuration(600);
|
||||||
|
fadeIn.setInterpolator(new AccelerateDecelerateInterpolator());
|
||||||
|
|
||||||
|
// 添加轻微缩放效果
|
||||||
|
ObjectAnimator scaleX = ObjectAnimator.ofFloat(wishTag, "scaleX", 0.8f, 1.05f, 1f);
|
||||||
|
scaleX.setDuration(600);
|
||||||
|
|
||||||
|
ObjectAnimator scaleY = ObjectAnimator.ofFloat(wishTag, "scaleY", 0.8f, 1.05f, 1f);
|
||||||
|
scaleY.setDuration(600);
|
||||||
|
|
||||||
|
AnimatorSet fadeInSet = new AnimatorSet();
|
||||||
|
fadeInSet.playTogether(fadeIn, scaleX, scaleY);
|
||||||
|
|
||||||
|
fadeInSet.addListener(new android.animation.AnimatorListenerAdapter() {
|
||||||
|
@Override
|
||||||
|
public void onAnimationEnd(android.animation.Animator animation) {
|
||||||
|
// 开始摇摆动画
|
||||||
|
startSwingAnimation(wishTag);
|
||||||
|
if (onComplete != null) {
|
||||||
|
onComplete.run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
fadeInSet.start();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
fadeOut.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 替换动画:旧心愿渐隐消失,新心愿从底部飘上来
|
||||||
|
* @param wishTag 心愿牌View
|
||||||
|
* @param newText 新心愿文字
|
||||||
|
* @param newBackground 新心愿背景资源
|
||||||
|
* @param startX 新心愿起始X坐标
|
||||||
|
* @param startY 新心愿起始Y坐标
|
||||||
|
* @param targetX 目标X坐标
|
||||||
|
* @param targetY 目标Y坐标
|
||||||
|
* @param onComplete 动画完成回调
|
||||||
|
*/
|
||||||
|
public static void animateReplaceWithFlyIn(android.widget.TextView wishTag, String newText,
|
||||||
|
int newBackground, float startX, float startY,
|
||||||
|
float targetX, float targetY, Runnable onComplete) {
|
||||||
|
// 保存原始位置
|
||||||
|
final float originalX = wishTag.getX();
|
||||||
|
final float originalY = wishTag.getY();
|
||||||
|
|
||||||
|
// 第一阶段:旧心愿渐隐消失(800ms)
|
||||||
|
ObjectAnimator fadeOut = ObjectAnimator.ofFloat(wishTag, "alpha", 1f, 0f);
|
||||||
|
fadeOut.setDuration(800);
|
||||||
|
fadeOut.setInterpolator(new AccelerateDecelerateInterpolator());
|
||||||
|
|
||||||
|
fadeOut.addListener(new android.animation.AnimatorListenerAdapter() {
|
||||||
|
@Override
|
||||||
|
public void onAnimationEnd(android.animation.Animator animation) {
|
||||||
|
// 更新内容和背景
|
||||||
|
wishTag.setText(newText);
|
||||||
|
wishTag.setBackgroundResource(newBackground);
|
||||||
|
|
||||||
|
// 设置到起始位置(屏幕底部)
|
||||||
|
wishTag.setX(startX);
|
||||||
|
wishTag.setY(startY);
|
||||||
|
wishTag.setAlpha(0f);
|
||||||
|
wishTag.setScaleX(0.5f);
|
||||||
|
wishTag.setScaleY(0.5f);
|
||||||
|
wishTag.setVisibility(View.VISIBLE);
|
||||||
|
|
||||||
|
// 第二阶段:新心愿从底部飘上来(1200ms)
|
||||||
|
AnimatorSet flyInSet = new AnimatorSet();
|
||||||
|
|
||||||
|
// 移动到目标位置
|
||||||
|
ObjectAnimator moveX = ObjectAnimator.ofFloat(wishTag, "x", startX, originalX);
|
||||||
|
moveX.setDuration(1200);
|
||||||
|
moveX.setInterpolator(new DecelerateInterpolator(1.5f));
|
||||||
|
|
||||||
|
ObjectAnimator moveY = ObjectAnimator.ofFloat(wishTag, "y", startY, originalY);
|
||||||
|
moveY.setDuration(1200);
|
||||||
|
moveY.setInterpolator(new DecelerateInterpolator(2f));
|
||||||
|
|
||||||
|
// 渐显
|
||||||
|
ObjectAnimator fadeIn = ObjectAnimator.ofFloat(wishTag, "alpha", 0f, 1f);
|
||||||
|
fadeIn.setDuration(800);
|
||||||
|
|
||||||
|
// 缩放
|
||||||
|
ObjectAnimator scaleX = ObjectAnimator.ofFloat(wishTag, "scaleX", 0.5f, 1.1f, 1f);
|
||||||
|
scaleX.setDuration(1200);
|
||||||
|
scaleX.setInterpolator(new OvershootInterpolator(1.2f));
|
||||||
|
|
||||||
|
ObjectAnimator scaleY = ObjectAnimator.ofFloat(wishTag, "scaleY", 0.5f, 1.1f, 1f);
|
||||||
|
scaleY.setDuration(1200);
|
||||||
|
scaleY.setInterpolator(new OvershootInterpolator(1.2f));
|
||||||
|
|
||||||
|
// 轻微旋转
|
||||||
|
ObjectAnimator rotate = ObjectAnimator.ofFloat(wishTag, "rotation", 0f, -5f, 5f, -3f, 3f, 0f);
|
||||||
|
rotate.setDuration(1500);
|
||||||
|
|
||||||
|
flyInSet.playTogether(moveX, moveY, fadeIn, scaleX, scaleY, rotate);
|
||||||
|
|
||||||
|
flyInSet.addListener(new android.animation.AnimatorListenerAdapter() {
|
||||||
|
@Override
|
||||||
|
public void onAnimationEnd(android.animation.Animator animation) {
|
||||||
|
// 确保位置正确
|
||||||
|
wishTag.setX(originalX);
|
||||||
|
wishTag.setY(originalY);
|
||||||
|
// 开始摇摆动画
|
||||||
|
startSwingAnimation(wishTag);
|
||||||
|
if (onComplete != null) {
|
||||||
|
onComplete.run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
flyInSet.start();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
fadeOut.start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
package com.example.livestreaming;
|
package com.example.livestreaming;
|
||||||
|
|
||||||
import android.app.Dialog;
|
import android.app.Dialog;
|
||||||
import android.app.ProgressDialog;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
|
|
@ -12,6 +11,7 @@ import android.os.Looper;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.Window;
|
import android.view.Window;
|
||||||
import android.widget.EditText;
|
import android.widget.EditText;
|
||||||
|
import android.widget.FrameLayout;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
@ -33,8 +33,10 @@ import java.text.SimpleDateFormat;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
import java.util.Queue;
|
||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
|
|
||||||
import retrofit2.Call;
|
import retrofit2.Call;
|
||||||
|
|
@ -43,7 +45,7 @@ import retrofit2.Response;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 许愿树页面
|
* 许愿树页面
|
||||||
* 数据通过API实时同步到服务端
|
* 新版本:心愿牌样式,带飘动动画
|
||||||
*/
|
*/
|
||||||
public class WishTreeActivity extends AppCompatActivity {
|
public class WishTreeActivity extends AppCompatActivity {
|
||||||
|
|
||||||
|
|
@ -52,12 +54,32 @@ public class WishTreeActivity extends AppCompatActivity {
|
||||||
private Runnable timerRunnable;
|
private Runnable timerRunnable;
|
||||||
private ApiService apiService;
|
private ApiService apiService;
|
||||||
|
|
||||||
// 心愿数据(从服务端获取)
|
// 心愿数据
|
||||||
private List<WishtreeResponse.Wish> myWishes = new ArrayList<>();
|
private List<WishtreeResponse.Wish> myWishes = new ArrayList<>();
|
||||||
// 当前节日
|
|
||||||
private WishtreeResponse.Festival currentFestival;
|
private WishtreeResponse.Festival currentFestival;
|
||||||
// 是否正在加载
|
|
||||||
private boolean isLoading = false;
|
// 心愿总数(从服务器获取)
|
||||||
|
private int totalWishCount = 0;
|
||||||
|
|
||||||
|
// 心愿牌View数组
|
||||||
|
private TextView[] wishTags;
|
||||||
|
|
||||||
|
// 心愿牌背景资源(不同颜色)
|
||||||
|
private final int[] tagBackgrounds = {
|
||||||
|
R.drawable.bg_wish_tag_pink,
|
||||||
|
R.drawable.bg_wish_tag_green,
|
||||||
|
R.drawable.bg_wish_tag_gold,
|
||||||
|
R.drawable.bg_wish_tag_blue,
|
||||||
|
R.drawable.bg_wish_tag_purple,
|
||||||
|
R.drawable.bg_wish_tag_yellow,
|
||||||
|
R.drawable.bg_wish_tag_orange,
|
||||||
|
R.drawable.bg_wish_tag_green,
|
||||||
|
R.drawable.bg_wish_tag_blue,
|
||||||
|
R.drawable.bg_wish_tag_pink
|
||||||
|
};
|
||||||
|
|
||||||
|
// 心愿牌位置队列(先进先出,记录心愿牌索引的添加顺序)
|
||||||
|
private Queue<Integer> wishTagQueue = new LinkedList<>();
|
||||||
|
|
||||||
public static void start(Context context) {
|
public static void start(Context context) {
|
||||||
context.startActivity(new Intent(context, WishTreeActivity.class));
|
context.startActivity(new Intent(context, WishTreeActivity.class));
|
||||||
|
|
@ -70,40 +92,58 @@ public class WishTreeActivity extends AppCompatActivity {
|
||||||
setContentView(binding.getRoot());
|
setContentView(binding.getRoot());
|
||||||
|
|
||||||
apiService = ApiClient.getService(this);
|
apiService = ApiClient.getService(this);
|
||||||
|
|
||||||
// 打印当前API地址和登录状态
|
|
||||||
String baseUrl = com.example.livestreaming.net.ApiClient.getCurrentBaseUrl(this);
|
|
||||||
String token = AuthStore.getToken(this);
|
|
||||||
android.util.Log.d("WishTree", "API地址: " + baseUrl);
|
|
||||||
android.util.Log.d("WishTree", "Token: " + (token != null && !token.isEmpty() ? "已登录" : "未登录"));
|
|
||||||
|
|
||||||
|
initWishTags();
|
||||||
startBannerCountdown();
|
startBannerCountdown();
|
||||||
setupBottomNav();
|
setupBottomNav();
|
||||||
setupWishCards();
|
|
||||||
setupMakeWishButton();
|
setupMakeWishButton();
|
||||||
setupTopBarButtons();
|
setupTopBarButtons();
|
||||||
|
setupWishTagClicks();
|
||||||
|
|
||||||
// 加载数据
|
|
||||||
loadCurrentFestival();
|
loadCurrentFestival();
|
||||||
loadMyWishes();
|
loadMyWishes();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化心愿牌数组
|
||||||
|
*/
|
||||||
|
private void initWishTags() {
|
||||||
|
wishTags = new TextView[]{
|
||||||
|
findViewById(R.id.wishTag1),
|
||||||
|
findViewById(R.id.wishTag2),
|
||||||
|
findViewById(R.id.wishTag3),
|
||||||
|
findViewById(R.id.wishTag4),
|
||||||
|
findViewById(R.id.wishTag5),
|
||||||
|
findViewById(R.id.wishTag6),
|
||||||
|
findViewById(R.id.wishTag7),
|
||||||
|
findViewById(R.id.wishTag8),
|
||||||
|
findViewById(R.id.wishTag9),
|
||||||
|
findViewById(R.id.wishTag10)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置顶部栏按钮
|
* 设置顶部栏按钮
|
||||||
*/
|
*/
|
||||||
private void setupTopBarButtons() {
|
private void setupTopBarButtons() {
|
||||||
// 搜索按钮
|
binding.searchButton.setOnClickListener(v -> SearchActivity.start(this));
|
||||||
binding.searchButton.setOnClickListener(v -> {
|
binding.notifyButton.setOnClickListener(v -> NotificationsActivity.start(this));
|
||||||
SearchActivity.start(this);
|
|
||||||
});
|
|
||||||
// 通知按钮
|
|
||||||
binding.notifyButton.setOnClickListener(v -> {
|
|
||||||
NotificationsActivity.start(this);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 检查是否已登录
|
* 设置心愿牌点击事件
|
||||||
|
*/
|
||||||
|
private void setupWishTagClicks() {
|
||||||
|
for (int i = 0; i < wishTags.length; i++) {
|
||||||
|
final int index = i;
|
||||||
|
if (wishTags[i] != null) {
|
||||||
|
wishTags[i].setOnClickListener(v -> onWishTagClick(index));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查登录状态
|
||||||
*/
|
*/
|
||||||
private boolean checkLogin() {
|
private boolean checkLogin() {
|
||||||
String token = AuthStore.getToken(this);
|
String token = AuthStore.getToken(this);
|
||||||
|
|
@ -141,7 +181,7 @@ public class WishTreeActivity extends AppCompatActivity {
|
||||||
*/
|
*/
|
||||||
private void updateBannerText() {
|
private void updateBannerText() {
|
||||||
if (currentFestival != null && binding != null) {
|
if (currentFestival != null && binding != null) {
|
||||||
String text = currentFestival.name + "许愿树 | 许下心愿,愿望成真";
|
String text = "✨ " + currentFestival.name + " | 许下心愿,愿望成真";
|
||||||
binding.bannerText.setText(text);
|
binding.bannerText.setText(text);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -150,92 +190,107 @@ public class WishTreeActivity extends AppCompatActivity {
|
||||||
* 从服务端加载我的心愿
|
* 从服务端加载我的心愿
|
||||||
*/
|
*/
|
||||||
private void loadMyWishes() {
|
private void loadMyWishes() {
|
||||||
android.util.Log.d("WishTree", "开始加载我的心愿列表");
|
// 重新加载时重置队列
|
||||||
|
resetWishTagQueue();
|
||||||
|
|
||||||
apiService.getMyWishes(1, 10).enqueue(new Callback<ApiResponse<WishtreeResponse.WishPage>>() {
|
apiService.getMyWishes(1, 10).enqueue(new Callback<ApiResponse<WishtreeResponse.WishPage>>() {
|
||||||
@Override
|
@Override
|
||||||
public void onResponse(@NonNull Call<ApiResponse<WishtreeResponse.WishPage>> call,
|
public void onResponse(@NonNull Call<ApiResponse<WishtreeResponse.WishPage>> call,
|
||||||
@NonNull Response<ApiResponse<WishtreeResponse.WishPage>> response) {
|
@NonNull Response<ApiResponse<WishtreeResponse.WishPage>> response) {
|
||||||
android.util.Log.d("WishTree", "加载心愿响应: code=" + response.code());
|
if (response.isSuccessful() && response.body() != null && response.body().getData() != null) {
|
||||||
if (response.isSuccessful() && response.body() != null) {
|
WishtreeResponse.WishPage page = response.body().getData();
|
||||||
android.util.Log.d("WishTree", "响应body: code=" + response.body().getCode());
|
myWishes = page.list;
|
||||||
if (response.body().getData() != null) {
|
if (myWishes == null) myWishes = new ArrayList<>();
|
||||||
myWishes = response.body().getData().list;
|
// 使用服务器返回的总数
|
||||||
if (myWishes == null) myWishes = new ArrayList<>();
|
totalWishCount = page.total;
|
||||||
android.util.Log.d("WishTree", "加载到 " + myWishes.size() + " 条心愿");
|
updateWishTags(false);
|
||||||
updateWishCards();
|
updateWishCount();
|
||||||
updateWishCount();
|
|
||||||
} else {
|
|
||||||
android.util.Log.w("WishTree", "响应数据为空");
|
|
||||||
myWishes = new ArrayList<>();
|
|
||||||
updateWishCards();
|
|
||||||
updateWishCount();
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
android.util.Log.e("WishTree", "加载心愿失败: " + response.code());
|
myWishes = new ArrayList<>();
|
||||||
try {
|
totalWishCount = 0;
|
||||||
if (response.errorBody() != null) {
|
updateWishTags(false);
|
||||||
android.util.Log.e("WishTree", "错误响应: " + response.errorBody().string());
|
updateWishCount();
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
android.util.Log.e("WishTree", "读取错误响应失败", e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onFailure(@NonNull Call<ApiResponse<WishtreeResponse.WishPage>> call, @NonNull Throwable t) {
|
public void onFailure(@NonNull Call<ApiResponse<WishtreeResponse.WishPage>> call, @NonNull Throwable t) {
|
||||||
android.util.Log.e("WishTree", "加载心愿网络错误", t);
|
|
||||||
Toast.makeText(WishTreeActivity.this, "加载心愿失败", Toast.LENGTH_SHORT).show();
|
Toast.makeText(WishTreeActivity.this, "加载心愿失败", Toast.LENGTH_SHORT).show();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新心愿卡片显示
|
* 更新心愿牌显示
|
||||||
|
* @param animate 是否播放动画
|
||||||
*/
|
*/
|
||||||
private void updateWishCards() {
|
private void updateWishTags(boolean animate) {
|
||||||
TextView[] cards = {
|
// 只在队列为空时初始化(首次加载或重新加载)
|
||||||
binding.wishCard1, binding.wishCard2, binding.wishCard3,
|
boolean needInitQueue = wishTagQueue.isEmpty();
|
||||||
binding.wishCard4, binding.wishCard5, binding.wishCard6, binding.wishCard7
|
|
||||||
};
|
for (int i = 0; i < wishTags.length; i++) {
|
||||||
for (int i = 0; i < cards.length; i++) {
|
if (wishTags[i] == null) continue;
|
||||||
|
|
||||||
if (i < myWishes.size() && myWishes.get(i) != null) {
|
if (i < myWishes.size() && myWishes.get(i) != null) {
|
||||||
String content = myWishes.get(i).content;
|
String content = myWishes.get(i).content;
|
||||||
String text = content.length() > 8 ? content.substring(0, 8) + "..." : content;
|
// 竖向显示文字,最多5个字
|
||||||
cards[i].setText(text);
|
String verticalText = formatVerticalText(content, 5);
|
||||||
|
wishTags[i].setText(verticalText);
|
||||||
|
wishTags[i].setBackgroundResource(tagBackgrounds[i % tagBackgrounds.length]);
|
||||||
|
|
||||||
|
// 只在首次加载时按顺序加入队列
|
||||||
|
if (needInitQueue) {
|
||||||
|
wishTagQueue.offer(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (animate) {
|
||||||
|
WishTagAnimator.animateAppear(wishTags[i], i * 150L);
|
||||||
|
} else {
|
||||||
|
wishTags[i].setVisibility(View.VISIBLE);
|
||||||
|
wishTags[i].setAlpha(1f);
|
||||||
|
WishTagAnimator.startSwingAnimation(wishTags[i]);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
cards[i].setText("");
|
wishTags[i].setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重新加载时重置队列
|
||||||
|
*/
|
||||||
|
private void resetWishTagQueue() {
|
||||||
|
wishTagQueue.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 格式化文字为竖向显示
|
||||||
|
*/
|
||||||
|
private String formatVerticalText(String text, int maxChars) {
|
||||||
|
if (text == null || text.isEmpty()) return "";
|
||||||
|
// 心愿牌较小,最多显示5个字
|
||||||
|
String trimmed = text.length() > maxChars ? text.substring(0, maxChars) : text;
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (int i = 0; i < trimmed.length(); i++) {
|
||||||
|
sb.append(trimmed.charAt(i));
|
||||||
|
if (i < trimmed.length() - 1) sb.append("\n");
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新祈愿值显示
|
* 更新祈愿值显示
|
||||||
*/
|
*/
|
||||||
private void updateWishCount() {
|
private void updateWishCount() {
|
||||||
int count = myWishes != null ? myWishes.size() : 0;
|
// 使用服务器返回的总数
|
||||||
binding.tvWishCount.setText("祈愿值:" + count + "/100");
|
binding.tvWishCount.setText("祈愿值:" + totalWishCount + "/100");
|
||||||
|
binding.progressWish.setProgress(Math.min(totalWishCount, 100));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置心愿卡片点击事件
|
* 心愿牌点击
|
||||||
*/
|
*/
|
||||||
private void setupWishCards() {
|
private void onWishTagClick(int index) {
|
||||||
TextView[] cards = {
|
|
||||||
binding.wishCard1, binding.wishCard2, binding.wishCard3,
|
|
||||||
binding.wishCard4, binding.wishCard5, binding.wishCard6, binding.wishCard7
|
|
||||||
};
|
|
||||||
for (int i = 0; i < cards.length; i++) {
|
|
||||||
final int index = i;
|
|
||||||
cards[i].setOnClickListener(v -> onWishCardClick(index));
|
|
||||||
}
|
|
||||||
binding.addWishCard.setOnClickListener(v -> showMakeWishInputDialog());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 心愿卡片点击
|
|
||||||
*/
|
|
||||||
private void onWishCardClick(int index) {
|
|
||||||
if (index < myWishes.size() && myWishes.get(index) != null) {
|
if (index < myWishes.size() && myWishes.get(index) != null) {
|
||||||
showViewWishDialog(index);
|
showViewWishDialog(index);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -243,11 +298,17 @@ public class WishTreeActivity extends AppCompatActivity {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置许愿按钮
|
||||||
|
*/
|
||||||
|
private void setupMakeWishButton() {
|
||||||
|
binding.btnMakeWish.setOnClickListener(v -> showMakeWishInputDialog());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 显示许愿输入对话框
|
* 显示许愿输入对话框
|
||||||
*/
|
*/
|
||||||
private void showMakeWishInputDialog() {
|
private void showMakeWishInputDialog() {
|
||||||
// 检查登录状态
|
|
||||||
if (!checkLogin()) return;
|
if (!checkLogin()) return;
|
||||||
|
|
||||||
Dialog dialog = new Dialog(this);
|
Dialog dialog = new Dialog(this);
|
||||||
|
|
@ -264,7 +325,6 @@ public class WishTreeActivity extends AppCompatActivity {
|
||||||
View btnCancel = dialog.findViewById(R.id.btnCancel);
|
View btnCancel = dialog.findViewById(R.id.btnCancel);
|
||||||
View btnMakeWish = dialog.findViewById(R.id.btnMakeWish);
|
View btnMakeWish = dialog.findViewById(R.id.btnMakeWish);
|
||||||
|
|
||||||
// 字数统计
|
|
||||||
input.addTextChangedListener(new android.text.TextWatcher() {
|
input.addTextChangedListener(new android.text.TextWatcher() {
|
||||||
@Override
|
@Override
|
||||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
|
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
|
||||||
|
|
@ -298,7 +358,6 @@ public class WishTreeActivity extends AppCompatActivity {
|
||||||
* 发布心愿到服务端
|
* 发布心愿到服务端
|
||||||
*/
|
*/
|
||||||
private void publishWish(String content, Dialog dialog) {
|
private void publishWish(String content, Dialog dialog) {
|
||||||
// 检查登录状态
|
|
||||||
String token = AuthStore.getToken(this);
|
String token = AuthStore.getToken(this);
|
||||||
if (token == null || token.isEmpty()) {
|
if (token == null || token.isEmpty()) {
|
||||||
Toast.makeText(this, "请先登录", Toast.LENGTH_SHORT).show();
|
Toast.makeText(this, "请先登录", Toast.LENGTH_SHORT).show();
|
||||||
|
|
@ -309,57 +368,155 @@ public class WishTreeActivity extends AppCompatActivity {
|
||||||
Integer festivalId = currentFestival != null ? currentFestival.id : null;
|
Integer festivalId = currentFestival != null ? currentFestival.id : null;
|
||||||
WishtreeRequest.PublishWish request = new WishtreeRequest.PublishWish(festivalId, content, null);
|
WishtreeRequest.PublishWish request = new WishtreeRequest.PublishWish(festivalId, content, null);
|
||||||
|
|
||||||
android.util.Log.d("WishTree", "发布心愿请求: festivalId=" + festivalId + ", content=" + content);
|
|
||||||
|
|
||||||
apiService.publishWish(request).enqueue(new Callback<ApiResponse<WishtreeResponse.Wish>>() {
|
apiService.publishWish(request).enqueue(new Callback<ApiResponse<WishtreeResponse.Wish>>() {
|
||||||
@Override
|
@Override
|
||||||
public void onResponse(@NonNull Call<ApiResponse<WishtreeResponse.Wish>> call,
|
public void onResponse(@NonNull Call<ApiResponse<WishtreeResponse.Wish>> call,
|
||||||
@NonNull Response<ApiResponse<WishtreeResponse.Wish>> response) {
|
@NonNull Response<ApiResponse<WishtreeResponse.Wish>> response) {
|
||||||
android.util.Log.d("WishTree", "发布心愿响应: code=" + response.code());
|
if (response.isSuccessful() && response.body() != null && response.body().isOk()) {
|
||||||
if (response.isSuccessful() && response.body() != null) {
|
dialog.dismiss();
|
||||||
android.util.Log.d("WishTree", "响应body: code=" + response.body().getCode() + ", msg=" + response.body().getMessage());
|
|
||||||
if (response.body().isOk()) {
|
// 添加新心愿到列表
|
||||||
dialog.dismiss();
|
WishtreeResponse.Wish newWish = response.body().getData();
|
||||||
|
if (newWish != null) {
|
||||||
|
myWishes.add(0, newWish);
|
||||||
|
|
||||||
|
// 增加总数
|
||||||
|
totalWishCount++;
|
||||||
|
|
||||||
|
// 播放飘动动画
|
||||||
|
animateNewWishTag(newWish);
|
||||||
|
|
||||||
|
updateWishCount();
|
||||||
showSuccessDialog();
|
showSuccessDialog();
|
||||||
loadMyWishes(); // 重新加载心愿列表
|
|
||||||
} else {
|
|
||||||
String msg = response.body().getMessage();
|
|
||||||
Toast.makeText(WishTreeActivity.this,
|
|
||||||
msg != null && !msg.isEmpty() ? msg : "发布失败",
|
|
||||||
Toast.LENGTH_SHORT).show();
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// 尝试读取错误响应
|
String msg = response.body() != null ? response.body().getMessage() : "发布失败";
|
||||||
String errorMsg = "发布失败";
|
Toast.makeText(WishTreeActivity.this, msg != null ? msg : "发布失败", Toast.LENGTH_SHORT).show();
|
||||||
try {
|
|
||||||
if (response.errorBody() != null) {
|
|
||||||
String errorBody = response.errorBody().string();
|
|
||||||
android.util.Log.e("WishTree", "错误响应: " + errorBody);
|
|
||||||
errorMsg = "发布失败: " + response.code();
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
android.util.Log.e("WishTree", "读取错误响应失败", e);
|
|
||||||
}
|
|
||||||
Toast.makeText(WishTreeActivity.this, errorMsg, Toast.LENGTH_SHORT).show();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onFailure(@NonNull Call<ApiResponse<WishtreeResponse.Wish>> call, @NonNull Throwable t) {
|
public void onFailure(@NonNull Call<ApiResponse<WishtreeResponse.Wish>> call, @NonNull Throwable t) {
|
||||||
android.util.Log.e("WishTree", "发布心愿网络错误", t);
|
Toast.makeText(WishTreeActivity.this, "网络错误", Toast.LENGTH_SHORT).show();
|
||||||
String errorMsg = "网络错误";
|
|
||||||
if (t instanceof java.net.UnknownHostException) {
|
|
||||||
errorMsg = "无法连接服务器,请检查网络";
|
|
||||||
} else if (t instanceof java.net.SocketTimeoutException) {
|
|
||||||
errorMsg = "连接超时,请重试";
|
|
||||||
} else if (t.getMessage() != null) {
|
|
||||||
errorMsg = "网络错误: " + t.getMessage();
|
|
||||||
}
|
|
||||||
Toast.makeText(WishTreeActivity.this, errorMsg, Toast.LENGTH_SHORT).show();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 播放新心愿飘到树上的动画
|
||||||
|
* 如果心愿数量超过10个,会替换最早的心愿(旧心愿渐隐,新心愿从底部飘上来)
|
||||||
|
*/
|
||||||
|
private void animateNewWishTag(WishtreeResponse.Wish wish) {
|
||||||
|
FrameLayout container = findViewById(R.id.wishTagsContainer);
|
||||||
|
if (container == null) return;
|
||||||
|
|
||||||
|
int currentCount = myWishes.size();
|
||||||
|
|
||||||
|
if (currentCount <= wishTags.length) {
|
||||||
|
// 心愿数量不超过10个,找一个空位置添加
|
||||||
|
int targetIndex = findEmptyOrRandomSlot();
|
||||||
|
if (targetIndex < 0 || targetIndex >= wishTags.length) return;
|
||||||
|
|
||||||
|
TextView targetTag = wishTags[targetIndex];
|
||||||
|
if (targetTag == null) return;
|
||||||
|
|
||||||
|
// 设置心愿内容
|
||||||
|
String verticalText = formatVerticalText(wish.content, 5);
|
||||||
|
targetTag.setText(verticalText);
|
||||||
|
targetTag.setBackgroundResource(tagBackgrounds[targetIndex % tagBackgrounds.length]);
|
||||||
|
|
||||||
|
// 将新位置加入队列末尾
|
||||||
|
wishTagQueue.offer(targetIndex);
|
||||||
|
|
||||||
|
// 从屏幕底部中央飘到目标位置
|
||||||
|
float startX = container.getWidth() / 2f - targetTag.getWidth() / 2f;
|
||||||
|
float startY = container.getHeight();
|
||||||
|
float targetX = targetTag.getX();
|
||||||
|
float targetY = targetTag.getY();
|
||||||
|
|
||||||
|
WishTagAnimator.animateWishToTree(targetTag, startX, startY, targetX, targetY, 1500, () -> {
|
||||||
|
// 动画完成后启动摇摆动画
|
||||||
|
WishTagAnimator.startSwingAnimation(targetTag);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// 心愿数量超过10个,从队列头部取出最早加入的心愿牌位置
|
||||||
|
Integer oldestIndex = wishTagQueue.poll();
|
||||||
|
if (oldestIndex == null) {
|
||||||
|
oldestIndex = 0; // 队列为空时默认第一个
|
||||||
|
}
|
||||||
|
|
||||||
|
TextView oldTag = wishTags[oldestIndex];
|
||||||
|
if (oldTag == null) return;
|
||||||
|
|
||||||
|
// 将这个位置重新加入队列末尾(因为新心愿会占用这个位置)
|
||||||
|
wishTagQueue.offer(oldestIndex);
|
||||||
|
|
||||||
|
// 设置新心愿内容
|
||||||
|
String verticalText = formatVerticalText(wish.content, 5);
|
||||||
|
int newBackground = tagBackgrounds[oldestIndex % tagBackgrounds.length];
|
||||||
|
|
||||||
|
// 获取目标位置
|
||||||
|
float targetX = oldTag.getX();
|
||||||
|
float targetY = oldTag.getY();
|
||||||
|
float startX = container.getWidth() / 2f - oldTag.getWidth() / 2f;
|
||||||
|
float startY = container.getHeight();
|
||||||
|
|
||||||
|
// 旧心愿渐隐消失,同时新心愿从底部飘上来
|
||||||
|
WishTagAnimator.animateReplaceWithFlyIn(oldTag, verticalText, newBackground,
|
||||||
|
startX, startY, targetX, targetY, () -> {
|
||||||
|
// 动画完成后启动摇摆动画
|
||||||
|
WishTagAnimator.startSwingAnimation(oldTag);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 找一个空位置或随机位置
|
||||||
|
*/
|
||||||
|
private int findEmptyOrRandomSlot() {
|
||||||
|
// 先找空位置
|
||||||
|
for (int i = 0; i < wishTags.length; i++) {
|
||||||
|
if (wishTags[i] != null && wishTags[i].getVisibility() == View.GONE) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 没有空位置,随机选一个
|
||||||
|
return (int) (Math.random() * wishTags.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保留原来的方法签名用于兼容
|
||||||
|
private void animateNewWishTagLegacy(WishtreeResponse.Wish wish) {
|
||||||
|
// 找到第一个可用的心愿牌位置
|
||||||
|
int targetIndex = Math.min(myWishes.size() - 1, wishTags.length - 1);
|
||||||
|
if (targetIndex < 0 || targetIndex >= wishTags.length) return;
|
||||||
|
|
||||||
|
TextView targetTag = wishTags[targetIndex];
|
||||||
|
if (targetTag == null) return;
|
||||||
|
|
||||||
|
// 设置心愿内容
|
||||||
|
String verticalText = formatVerticalText(wish.content, 5);
|
||||||
|
targetTag.setText(verticalText);
|
||||||
|
targetTag.setBackgroundResource(tagBackgrounds[targetIndex % tagBackgrounds.length]);
|
||||||
|
|
||||||
|
// 获取目标位置
|
||||||
|
FrameLayout container = findViewById(R.id.wishTagsContainer);
|
||||||
|
if (container == null) return;
|
||||||
|
|
||||||
|
// 计算目标位置
|
||||||
|
float targetX = targetTag.getX();
|
||||||
|
float targetY = targetTag.getY();
|
||||||
|
|
||||||
|
// 从屏幕底部中央开始
|
||||||
|
float startX = container.getWidth() / 2f - targetTag.getWidth() / 2f;
|
||||||
|
float startY = container.getHeight();
|
||||||
|
|
||||||
|
// 执行动画
|
||||||
|
WishTagAnimator.animateWishToTree(targetTag, startX, startY, targetX, targetY, 1500, () -> {
|
||||||
|
// 动画完成后更新其他心愿牌
|
||||||
|
updateWishTags(false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 显示成功对话框
|
* 显示成功对话框
|
||||||
*/
|
*/
|
||||||
|
|
@ -397,38 +554,27 @@ public class WishTreeActivity extends AppCompatActivity {
|
||||||
|
|
||||||
tvContent.setText(wish.content);
|
tvContent.setText(wish.content);
|
||||||
|
|
||||||
// 显示点赞数和评论数
|
|
||||||
TextView tvLikeCount = dialog.findViewById(R.id.tvLikeCount);
|
TextView tvLikeCount = dialog.findViewById(R.id.tvLikeCount);
|
||||||
TextView tvCommentCount = dialog.findViewById(R.id.tvCommentCount);
|
TextView tvCommentCount = dialog.findViewById(R.id.tvCommentCount);
|
||||||
if (tvLikeCount != null) {
|
if (tvLikeCount != null) tvLikeCount.setText("❤ " + wish.likeCount);
|
||||||
tvLikeCount.setText("❤ " + wish.likeCount);
|
if (tvCommentCount != null) tvCommentCount.setText("💬 " + wish.commentCount);
|
||||||
}
|
|
||||||
if (tvCommentCount != null) {
|
|
||||||
tvCommentCount.setText("💬 " + wish.commentCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
btnClose.setOnClickListener(v -> dialog.dismiss());
|
btnClose.setOnClickListener(v -> dialog.dismiss());
|
||||||
|
|
||||||
// 删除心愿 - 添加确认对话框
|
|
||||||
btnDelete.setOnClickListener(v -> {
|
btnDelete.setOnClickListener(v -> {
|
||||||
new AlertDialog.Builder(this)
|
new AlertDialog.Builder(this)
|
||||||
.setTitle("确认删除")
|
.setTitle("确认删除")
|
||||||
.setMessage("确定要删除这个心愿吗?")
|
.setMessage("确定要删除这个心愿吗?")
|
||||||
.setPositiveButton("删除", (d, w) -> {
|
.setPositiveButton("删除", (d, w) -> deleteWish(wish.id, dialog, index))
|
||||||
deleteWish(wish.id, dialog, false);
|
|
||||||
})
|
|
||||||
.setNegativeButton("取消", null)
|
.setNegativeButton("取消", null)
|
||||||
.show();
|
.show();
|
||||||
});
|
});
|
||||||
|
|
||||||
// 愿望达成 - 添加确认对话框
|
|
||||||
btnComplete.setOnClickListener(v -> {
|
btnComplete.setOnClickListener(v -> {
|
||||||
new AlertDialog.Builder(this)
|
new AlertDialog.Builder(this)
|
||||||
.setTitle("愿望达成")
|
.setTitle("愿望达成")
|
||||||
.setMessage("恭喜!确认愿望已经达成了吗?")
|
.setMessage("恭喜!确认愿望已经达成了吗?")
|
||||||
.setPositiveButton("确认", (d, w) -> {
|
.setPositiveButton("确认", (d, w) -> deleteWish(wish.id, dialog, index))
|
||||||
deleteWish(wish.id, dialog, true);
|
|
||||||
})
|
|
||||||
.setNegativeButton("取消", null)
|
.setNegativeButton("取消", null)
|
||||||
.show();
|
.show();
|
||||||
});
|
});
|
||||||
|
|
@ -438,23 +584,25 @@ public class WishTreeActivity extends AppCompatActivity {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 删除心愿
|
* 删除心愿
|
||||||
* @param wishId 心愿ID
|
|
||||||
* @param dialog 对话框
|
|
||||||
* @param isComplete 是否是愿望达成
|
|
||||||
*/
|
*/
|
||||||
private void deleteWish(long wishId, Dialog dialog, boolean isComplete) {
|
private void deleteWish(long wishId, Dialog dialog, int index) {
|
||||||
apiService.deleteMyWish(wishId).enqueue(new Callback<ApiResponse<String>>() {
|
apiService.deleteMyWish(wishId).enqueue(new Callback<ApiResponse<String>>() {
|
||||||
@Override
|
@Override
|
||||||
public void onResponse(@NonNull Call<ApiResponse<String>> call,
|
public void onResponse(@NonNull Call<ApiResponse<String>> call,
|
||||||
@NonNull Response<ApiResponse<String>> response) {
|
@NonNull Response<ApiResponse<String>> response) {
|
||||||
if (response.isSuccessful() && response.body() != null && response.body().isOk()) {
|
if (response.isSuccessful() && response.body() != null && response.body().isOk()) {
|
||||||
dialog.dismiss();
|
dialog.dismiss();
|
||||||
if (isComplete) {
|
|
||||||
showCompleteSuccessDialog();
|
// 播放消失动画
|
||||||
|
if (index < wishTags.length && wishTags[index] != null) {
|
||||||
|
WishTagAnimator.animateDisappear(wishTags[index], () -> {
|
||||||
|
loadMyWishes();
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
Toast.makeText(WishTreeActivity.this, "心愿已删除", Toast.LENGTH_SHORT).show();
|
loadMyWishes();
|
||||||
}
|
}
|
||||||
loadMyWishes(); // 重新加载
|
|
||||||
|
Toast.makeText(WishTreeActivity.this, "心愿已删除", Toast.LENGTH_SHORT).show();
|
||||||
} else {
|
} else {
|
||||||
Toast.makeText(WishTreeActivity.this, "操作失败", Toast.LENGTH_SHORT).show();
|
Toast.makeText(WishTreeActivity.this, "操作失败", Toast.LENGTH_SHORT).show();
|
||||||
}
|
}
|
||||||
|
|
@ -467,24 +615,6 @@ public class WishTreeActivity extends AppCompatActivity {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 显示愿望达成成功对话框
|
|
||||||
*/
|
|
||||||
private void showCompleteSuccessDialog() {
|
|
||||||
Dialog dialog = new Dialog(this);
|
|
||||||
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
|
|
||||||
dialog.setContentView(R.layout.dialog_wish_complete);
|
|
||||||
if (dialog.getWindow() != null) {
|
|
||||||
dialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
|
|
||||||
}
|
|
||||||
dialog.show();
|
|
||||||
handler.postDelayed(dialog::dismiss, 2000);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setupMakeWishButton() {
|
|
||||||
binding.btnMakeWish.setOnClickListener(v -> showMakeWishInputDialog());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setupBottomNav() {
|
private void setupBottomNav() {
|
||||||
BottomNavigationView bottomNav = binding.bottomNavInclude.bottomNavigation;
|
BottomNavigationView bottomNav = binding.bottomNavInclude.bottomNavigation;
|
||||||
bottomNav.setSelectedItemId(R.id.nav_wish_tree);
|
bottomNav.setSelectedItemId(R.id.nav_wish_tree);
|
||||||
|
|
@ -561,9 +691,7 @@ public class WishTreeActivity extends AppCompatActivity {
|
||||||
long h = diff / 3600000;
|
long h = diff / 3600000;
|
||||||
long m = (diff % 3600000) / 60000;
|
long m = (diff % 3600000) / 60000;
|
||||||
long s = (diff % 60000) / 1000;
|
long s = (diff % 60000) / 1000;
|
||||||
SimpleDateFormat fmt = new SimpleDateFormat("HH:mm:ss", Locale.getDefault());
|
binding.bannerTimer.setText(String.format(Locale.getDefault(), "%02d:%02d:%02d", h, m, s));
|
||||||
fmt.setTimeZone(tz);
|
|
||||||
binding.bannerTimer.setText(fmt.format(new Date(now)) + " " + String.format(Locale.getDefault(), "%02d:%02d:%02d", h, m, s));
|
|
||||||
} catch (Exception ignored) {}
|
} catch (Exception ignored) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -574,7 +702,6 @@ public class WishTreeActivity extends AppCompatActivity {
|
||||||
binding.bottomNavInclude.bottomNavigation.setSelectedItemId(R.id.nav_wish_tree);
|
binding.bottomNavInclude.bottomNavigation.setSelectedItemId(R.id.nav_wish_tree);
|
||||||
UnreadMessageManager.updateBadge(binding.bottomNavInclude.bottomNavigation);
|
UnreadMessageManager.updateBadge(binding.bottomNavInclude.bottomNavigation);
|
||||||
}
|
}
|
||||||
// 每次返回页面时刷新数据
|
|
||||||
loadMyWishes();
|
loadMyWishes();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -112,11 +112,57 @@ public class WorkDetailActivity extends AppCompatActivity {
|
||||||
// 设置作品描述
|
// 设置作品描述
|
||||||
setupDescription();
|
setupDescription();
|
||||||
|
|
||||||
// 显示媒体内容
|
// 判断内容类型
|
||||||
if (workItem.getType() == WorkItem.WorkType.VIDEO) {
|
boolean hasVideo = workItem.getType() == WorkItem.WorkType.VIDEO ||
|
||||||
// 显示视频(暂时显示封面图,后续可以集成ExoPlayer)
|
!TextUtils.isEmpty(workItem.getVideoUrl());
|
||||||
|
|
||||||
|
// 检查是否有有效的图片列表(不包括封面,因为封面可能是无效的占位图)
|
||||||
|
boolean hasValidImageList = false;
|
||||||
|
List<String> imageUrls = workItem.getImageUrls();
|
||||||
|
if (imageUrls != null && !imageUrls.isEmpty()) {
|
||||||
|
for (String url : imageUrls) {
|
||||||
|
if (url != null && !url.isEmpty() && !isTextOnlyPlaceholder(url)) {
|
||||||
|
hasValidImageList = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查imageUris
|
||||||
|
List<Uri> imageUris = workItem.getImageUris();
|
||||||
|
if (!hasValidImageList && imageUris != null && !imageUris.isEmpty()) {
|
||||||
|
for (Uri uri : imageUris) {
|
||||||
|
if (uri != null && !isTextOnlyPlaceholder(uri.toString())) {
|
||||||
|
hasValidImageList = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String content = workItem.getDescription();
|
||||||
|
boolean hasContent = !TextUtils.isEmpty(content);
|
||||||
|
|
||||||
|
// 判断是否为纯文字动态:
|
||||||
|
// 核心逻辑:如果没有图片列表、没有视频,且有文字内容,就是纯文字动态
|
||||||
|
boolean isTextOnly = !hasValidImageList && !hasVideo && hasContent;
|
||||||
|
|
||||||
|
android.util.Log.d("WorkDetail", "内容类型判断: hasVideo=" + hasVideo +
|
||||||
|
", hasValidImageList=" + hasValidImageList + ", hasContent=" + hasContent +
|
||||||
|
", isTextOnly=" + isTextOnly);
|
||||||
|
|
||||||
|
if (isTextOnly) {
|
||||||
|
// 纯文字动态:显示文字内容区域
|
||||||
|
binding.imageViewPager.setVisibility(View.GONE);
|
||||||
|
binding.videoContainer.setVisibility(View.GONE);
|
||||||
|
binding.textContentContainer.setVisibility(View.VISIBLE);
|
||||||
|
binding.textContentText.setText(content);
|
||||||
|
|
||||||
|
android.util.Log.d("WorkDetail", "显示纯文字动态: " + content);
|
||||||
|
} else if (hasVideo) {
|
||||||
|
// 显示视频
|
||||||
binding.imageViewPager.setVisibility(View.GONE);
|
binding.imageViewPager.setVisibility(View.GONE);
|
||||||
binding.videoContainer.setVisibility(View.VISIBLE);
|
binding.videoContainer.setVisibility(View.VISIBLE);
|
||||||
|
binding.textContentContainer.setVisibility(View.GONE);
|
||||||
|
|
||||||
// 使用封面URI或视频URI显示预览图
|
// 使用封面URI或视频URI显示预览图
|
||||||
Uri videoUri = workItem.getVideoUri();
|
Uri videoUri = workItem.getVideoUri();
|
||||||
|
|
@ -162,16 +208,18 @@ public class WorkDetailActivity extends AppCompatActivity {
|
||||||
// 显示图片
|
// 显示图片
|
||||||
binding.videoContainer.setVisibility(View.GONE);
|
binding.videoContainer.setVisibility(View.GONE);
|
||||||
binding.imageViewPager.setVisibility(View.VISIBLE);
|
binding.imageViewPager.setVisibility(View.VISIBLE);
|
||||||
|
binding.textContentContainer.setVisibility(View.GONE);
|
||||||
|
|
||||||
List<Uri> imageUris = workItem.getImageUris();
|
// 重新获取imageUris(不重复定义变量)
|
||||||
|
List<Uri> displayImageUris = workItem.getImageUris();
|
||||||
// 如果 imageUris 为空,尝试从 imageUrls 恢复
|
// 如果 imageUris 为空,尝试从 imageUrls 恢复
|
||||||
if ((imageUris == null || imageUris.isEmpty()) && workItem.getImageUrls() != null && !workItem.getImageUrls().isEmpty()) {
|
if ((displayImageUris == null || displayImageUris.isEmpty()) && workItem.getImageUrls() != null && !workItem.getImageUrls().isEmpty()) {
|
||||||
imageUris = new ArrayList<>();
|
displayImageUris = new ArrayList<>();
|
||||||
for (String url : workItem.getImageUrls()) {
|
for (String url : workItem.getImageUrls()) {
|
||||||
if (url != null && !url.isEmpty()) {
|
if (url != null && !url.isEmpty()) {
|
||||||
try {
|
try {
|
||||||
Uri uri = Uri.parse(url);
|
Uri uri = Uri.parse(url);
|
||||||
imageUris.add(uri);
|
displayImageUris.add(uri);
|
||||||
android.util.Log.d("WorkDetail", "恢复图片URI: " + uri);
|
android.util.Log.d("WorkDetail", "恢复图片URI: " + uri);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
android.util.Log.e("WorkDetail", "解析图片URI失败: " + url, e);
|
android.util.Log.e("WorkDetail", "解析图片URI失败: " + url, e);
|
||||||
|
|
@ -181,28 +229,35 @@ public class WorkDetailActivity extends AppCompatActivity {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果还是没有图片,尝试使用封面
|
// 如果还是没有图片,尝试使用封面
|
||||||
if ((imageUris == null || imageUris.isEmpty()) && workItem.getCoverUri() != null) {
|
if ((displayImageUris == null || displayImageUris.isEmpty()) && workItem.getCoverUri() != null) {
|
||||||
imageUris = new ArrayList<>();
|
displayImageUris = new ArrayList<>();
|
||||||
imageUris.add(workItem.getCoverUri());
|
displayImageUris.add(workItem.getCoverUri());
|
||||||
android.util.Log.d("WorkDetail", "使用封面作为图片: " + workItem.getCoverUri());
|
android.util.Log.d("WorkDetail", "使用封面作为图片: " + workItem.getCoverUri());
|
||||||
} else if ((imageUris == null || imageUris.isEmpty()) && !TextUtils.isEmpty(workItem.getCoverUrl())) {
|
} else if ((displayImageUris == null || displayImageUris.isEmpty()) && !TextUtils.isEmpty(workItem.getCoverUrl())) {
|
||||||
try {
|
try {
|
||||||
imageUris = new ArrayList<>();
|
displayImageUris = new ArrayList<>();
|
||||||
imageUris.add(Uri.parse(workItem.getCoverUrl()));
|
displayImageUris.add(Uri.parse(workItem.getCoverUrl()));
|
||||||
android.util.Log.d("WorkDetail", "使用封面URL作为图片: " + workItem.getCoverUrl());
|
android.util.Log.d("WorkDetail", "使用封面URL作为图片: " + workItem.getCoverUrl());
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
android.util.Log.e("WorkDetail", "解析封面URL失败", e);
|
android.util.Log.e("WorkDetail", "解析封面URL失败", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (imageUris != null && !imageUris.isEmpty()) {
|
if (displayImageUris != null && !displayImageUris.isEmpty()) {
|
||||||
android.util.Log.d("WorkDetail", "显示图片数量: " + imageUris.size());
|
android.util.Log.d("WorkDetail", "显示图片数量: " + displayImageUris.size());
|
||||||
imageAdapter = new ImagePagerAdapter(imageUris);
|
imageAdapter = new ImagePagerAdapter(displayImageUris);
|
||||||
binding.imageViewPager.setAdapter(imageAdapter);
|
binding.imageViewPager.setAdapter(imageAdapter);
|
||||||
} else {
|
} else {
|
||||||
android.util.Log.w("WorkDetail", "没有可显示的图片");
|
android.util.Log.w("WorkDetail", "没有可显示的图片");
|
||||||
binding.imageViewPager.setVisibility(View.GONE);
|
// 如果没有图片但有内容,显示纯文字
|
||||||
Toast.makeText(this, "图片加载失败", Toast.LENGTH_SHORT).show();
|
if (hasContent) {
|
||||||
|
binding.imageViewPager.setVisibility(View.GONE);
|
||||||
|
binding.textContentContainer.setVisibility(View.VISIBLE);
|
||||||
|
binding.textContentText.setText(content);
|
||||||
|
} else {
|
||||||
|
binding.imageViewPager.setVisibility(View.GONE);
|
||||||
|
Toast.makeText(this, "暂无内容", Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1322,5 +1377,47 @@ public class WorkDetailActivity extends AppCompatActivity {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断URL是否为纯文字动态的占位图
|
||||||
|
* 后端为纯文字动态设置的特殊封面地址
|
||||||
|
*/
|
||||||
|
private boolean isTextOnlyPlaceholder(String url) {
|
||||||
|
if (url == null || url.trim().isEmpty()) {
|
||||||
|
return true; // 空URL也视为占位图
|
||||||
|
}
|
||||||
|
|
||||||
|
// 特殊占位图地址列表
|
||||||
|
String[] placeholderPatterns = {
|
||||||
|
"TEXT_ONLY_DYNAMIC_PLACEHOLDER", // Android端发布纯文字动态时设置的标识
|
||||||
|
"text_only_placeholder", // 纯文字动态占位图标识
|
||||||
|
"placeholder/text", // 文字占位图路径
|
||||||
|
"default_text_cover", // 默认文字封面
|
||||||
|
"no_image_placeholder", // 无图片占位图
|
||||||
|
"/placeholder.", // 通用占位图
|
||||||
|
"crmebimage/public/content/", // 后端默认内容图片路径
|
||||||
|
"default_cover", // 默认封面
|
||||||
|
"empty_cover", // 空封面
|
||||||
|
};
|
||||||
|
|
||||||
|
String lowerUrl = url.toLowerCase();
|
||||||
|
for (String pattern : placeholderPatterns) {
|
||||||
|
if (lowerUrl.contains(pattern.toLowerCase())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否为空白图片或默认图片(根据文件名判断)
|
||||||
|
if (lowerUrl.endsWith("/default.png") ||
|
||||||
|
lowerUrl.endsWith("/default.jpg") ||
|
||||||
|
lowerUrl.endsWith("/placeholder.png") ||
|
||||||
|
lowerUrl.endsWith("/placeholder.jpg") ||
|
||||||
|
lowerUrl.endsWith("/empty.png") ||
|
||||||
|
lowerUrl.endsWith("/empty.jpg")) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,10 @@ public class WorksAdapter extends RecyclerView.Adapter<WorksAdapter.WorksViewHol
|
||||||
}
|
}
|
||||||
|
|
||||||
static class WorksViewHolder extends RecyclerView.ViewHolder {
|
static class WorksViewHolder extends RecyclerView.ViewHolder {
|
||||||
|
private final View coverContainer;
|
||||||
|
private final View textContentContainer;
|
||||||
private final ImageView coverImage;
|
private final ImageView coverImage;
|
||||||
|
private final TextView contentText;
|
||||||
private final TextView titleText;
|
private final TextView titleText;
|
||||||
private final TextView authorText;
|
private final TextView authorText;
|
||||||
private final TextView likeCountText;
|
private final TextView likeCountText;
|
||||||
|
|
@ -67,7 +70,10 @@ public class WorksAdapter extends RecyclerView.Adapter<WorksAdapter.WorksViewHol
|
||||||
|
|
||||||
public WorksViewHolder(@NonNull View itemView) {
|
public WorksViewHolder(@NonNull View itemView) {
|
||||||
super(itemView);
|
super(itemView);
|
||||||
|
coverContainer = itemView.findViewById(R.id.coverContainer);
|
||||||
|
textContentContainer = itemView.findViewById(R.id.textContentContainer);
|
||||||
coverImage = itemView.findViewById(R.id.worksCoverImage);
|
coverImage = itemView.findViewById(R.id.worksCoverImage);
|
||||||
|
contentText = itemView.findViewById(R.id.worksContentText);
|
||||||
titleText = itemView.findViewById(R.id.worksTitleText);
|
titleText = itemView.findViewById(R.id.worksTitleText);
|
||||||
authorText = itemView.findViewById(R.id.worksAuthorText);
|
authorText = itemView.findViewById(R.id.worksAuthorText);
|
||||||
likeCountText = itemView.findViewById(R.id.worksLikeCountText);
|
likeCountText = itemView.findViewById(R.id.worksLikeCountText);
|
||||||
|
|
@ -82,18 +88,36 @@ public class WorksAdapter extends RecyclerView.Adapter<WorksAdapter.WorksViewHol
|
||||||
"title=" + works.getTitle() +
|
"title=" + works.getTitle() +
|
||||||
", userName=" + works.getUserName() +
|
", userName=" + works.getUserName() +
|
||||||
", authorName=" + works.getAuthorName() +
|
", authorName=" + works.getAuthorName() +
|
||||||
", likeCount=" + works.getLikeCount());
|
", likeCount=" + works.getLikeCount() +
|
||||||
|
", coverUrl=" + works.getCoverUrl());
|
||||||
|
|
||||||
// 设置封面图片
|
// 判断是否有有效封面(排除纯文字动态标记)
|
||||||
if (works.getCoverUrl() != null && !works.getCoverUrl().isEmpty()) {
|
String coverUrl = works.getCoverUrl();
|
||||||
|
boolean hasValidCover = coverUrl != null && !coverUrl.isEmpty()
|
||||||
|
&& !coverUrl.equals("text_only"); // 排除纯文字动态标记
|
||||||
|
|
||||||
|
if (hasValidCover) {
|
||||||
|
// 有封面:显示封面图片
|
||||||
|
coverContainer.setVisibility(View.VISIBLE);
|
||||||
|
textContentContainer.setVisibility(View.GONE);
|
||||||
|
|
||||||
Glide.with(itemView.getContext())
|
Glide.with(itemView.getContext())
|
||||||
.load(works.getCoverUrl())
|
.load(coverUrl)
|
||||||
.centerCrop()
|
.centerCrop()
|
||||||
.placeholder(R.drawable.bg_cover_placeholder)
|
.placeholder(R.drawable.bg_cover_placeholder)
|
||||||
.error(R.drawable.bg_cover_placeholder)
|
.error(R.drawable.bg_cover_placeholder)
|
||||||
.into(coverImage);
|
.into(coverImage);
|
||||||
} else {
|
} else {
|
||||||
coverImage.setImageResource(R.drawable.bg_cover_placeholder);
|
// 无封面:显示文字内容
|
||||||
|
coverContainer.setVisibility(View.GONE);
|
||||||
|
textContentContainer.setVisibility(View.VISIBLE);
|
||||||
|
|
||||||
|
String content = works.getDescription();
|
||||||
|
if (content != null && !content.isEmpty()) {
|
||||||
|
contentText.setText(content);
|
||||||
|
} else {
|
||||||
|
contentText.setText("暂无内容");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 设置标题
|
// 设置标题
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ public class WorksResponse {
|
||||||
private Long id; // 作品ID
|
private Long id; // 作品ID
|
||||||
private String title; // 作品标题
|
private String title; // 作品标题
|
||||||
private String description; // 作品描述
|
private String description; // 作品描述
|
||||||
|
private String content; // 作品内容(纯文字动态)
|
||||||
private String type; // 作品类型:IMAGE 或 VIDEO
|
private String type; // 作品类型:IMAGE 或 VIDEO
|
||||||
private String coverUrl; // 封面图片URL
|
private String coverUrl; // 封面图片URL
|
||||||
private String videoUrl; // 视频URL(视频作品)
|
private String videoUrl; // 视频URL(视频作品)
|
||||||
|
|
@ -29,6 +30,8 @@ public class WorksResponse {
|
||||||
private Boolean isOwner; // 是否是当前用户的作品
|
private Boolean isOwner; // 是否是当前用户的作品
|
||||||
private Integer isHot; // 是否热门:1-是 0-否
|
private Integer isHot; // 是否热门:1-是 0-否
|
||||||
private String hotTime; // 设置热门的时间
|
private String hotTime; // 设置热门的时间
|
||||||
|
private String category; // 分类编码
|
||||||
|
private String categoryName; // 分类名称
|
||||||
|
|
||||||
public Long getId() {
|
public Long getId() {
|
||||||
return id;
|
return id;
|
||||||
|
|
@ -47,12 +50,28 @@ public class WorksResponse {
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getDescription() {
|
public String getDescription() {
|
||||||
return description;
|
// 优先返回description,如果为空则返回content
|
||||||
|
if (description != null && !description.isEmpty()) {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
return content;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setDescription(String description) {
|
public void setDescription(String description) {
|
||||||
this.description = description;
|
this.description = description;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getContent() {
|
||||||
|
// 优先返回content,如果为空则返回description
|
||||||
|
if (content != null && !content.isEmpty()) {
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setContent(String content) {
|
||||||
|
this.content = content;
|
||||||
|
}
|
||||||
|
|
||||||
public String getType() {
|
public String getType() {
|
||||||
return type;
|
return type;
|
||||||
|
|
@ -223,4 +242,20 @@ public class WorksResponse {
|
||||||
public void setHotTime(String hotTime) {
|
public void setHotTime(String hotTime) {
|
||||||
this.hotTime = hotTime;
|
this.hotTime = hotTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getCategory() {
|
||||||
|
return category;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCategory(String category) {
|
||||||
|
this.category = category;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCategoryName() {
|
||||||
|
return categoryName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCategoryName(String categoryName) {
|
||||||
|
this.categoryName = categoryName;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- 底部导航图标颜色 - 选中时金色发光 -->
|
<!-- 底部导航图标颜色 - 选中时紫色 -->
|
||||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<item android:color="#FFD700" android:state_checked="true" />
|
<item android:color="#A855F7" android:state_checked="true" />
|
||||||
<item android:color="#99FFFFFF" android:state_checked="false" />
|
<item android:color="#999999" android:state_checked="false" />
|
||||||
</selector>
|
</selector>
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,18 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- 底部导航 - 深紫色半透明 + 顶部微光边 -->
|
<!-- 底部导航 - 白色背景 + 顶部灰色边线 -->
|
||||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<!-- 深紫色半透明背景 -->
|
<!-- 白色背景 -->
|
||||||
<item>
|
<item>
|
||||||
<shape android:shape="rectangle">
|
<shape android:shape="rectangle">
|
||||||
<solid android:color="#F0121225" />
|
<solid android:color="#FFFFFF" />
|
||||||
</shape>
|
</shape>
|
||||||
</item>
|
</item>
|
||||||
<!-- 顶部微光边线 -->
|
<!-- 顶部灰色边线 -->
|
||||||
<item android:bottom="-1dp" android:left="-1dp" android:right="-1dp">
|
<item android:bottom="-1dp" android:left="-1dp" android:right="-1dp">
|
||||||
<shape android:shape="rectangle">
|
<shape android:shape="rectangle">
|
||||||
<stroke
|
<stroke
|
||||||
android:width="1dp"
|
android:width="0.5dp"
|
||||||
android:color="#20A855F7" />
|
android:color="#E5E5E5" />
|
||||||
</shape>
|
</shape>
|
||||||
</item>
|
</item>
|
||||||
</layer-list>
|
</layer-list>
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:shape="rectangle">
|
android:shape="rectangle">
|
||||||
<corners android:radius="8dp" />
|
|
||||||
<stroke
|
<stroke
|
||||||
android:width="1dp"
|
android:width="1dp"
|
||||||
android:color="#CCCCCC"
|
android:color="#CCCCCC"
|
||||||
android:dashWidth="4dp"
|
android:dashWidth="4dp"
|
||||||
android:dashGap="2dp" />
|
android:dashGap="2dp" />
|
||||||
|
<corners android:radius="8dp" />
|
||||||
<solid android:color="#F5F5F5" />
|
<solid android:color="#F5F5F5" />
|
||||||
</shape>
|
</shape>
|
||||||
|
|
|
||||||
9
android-app/app/src/main/res/drawable/bg_spinner.xml
Normal file
9
android-app/app/src/main/res/drawable/bg_spinner.xml
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="rectangle">
|
||||||
|
<stroke
|
||||||
|
android:width="1dp"
|
||||||
|
android:color="#DDDDDD" />
|
||||||
|
<corners android:radius="8dp" />
|
||||||
|
<solid android:color="#FFFFFF" />
|
||||||
|
</shape>
|
||||||
22
android-app/app/src/main/res/drawable/bg_wish_tag_blue.xml
Normal file
22
android-app/app/src/main/res/drawable/bg_wish_tag_blue.xml
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<!-- 绳子 -->
|
||||||
|
<item
|
||||||
|
android:gravity="top|center_horizontal"
|
||||||
|
android:top="0dp"
|
||||||
|
android:left="12dp"
|
||||||
|
android:right="12dp">
|
||||||
|
<shape android:shape="rectangle">
|
||||||
|
<solid android:color="#A0522D"/>
|
||||||
|
<size android:width="2dp" android:height="12dp"/>
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
<!-- 许愿牌主体 -->
|
||||||
|
<item android:top="10dp">
|
||||||
|
<shape android:shape="rectangle">
|
||||||
|
<solid android:color="#87CEEB"/>
|
||||||
|
<corners android:radius="3dp"/>
|
||||||
|
<stroke android:width="0.5dp" android:color="#4169E1"/>
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
</layer-list>
|
||||||
22
android-app/app/src/main/res/drawable/bg_wish_tag_gold.xml
Normal file
22
android-app/app/src/main/res/drawable/bg_wish_tag_gold.xml
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<!-- 绳子 -->
|
||||||
|
<item
|
||||||
|
android:gravity="top|center_horizontal"
|
||||||
|
android:top="0dp"
|
||||||
|
android:left="12dp"
|
||||||
|
android:right="12dp">
|
||||||
|
<shape android:shape="rectangle">
|
||||||
|
<solid android:color="#A0522D"/>
|
||||||
|
<size android:width="2dp" android:height="12dp"/>
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
<!-- 许愿牌主体 - 金色 -->
|
||||||
|
<item android:top="10dp">
|
||||||
|
<shape android:shape="rectangle">
|
||||||
|
<solid android:color="#F5DEB3"/>
|
||||||
|
<corners android:radius="3dp"/>
|
||||||
|
<stroke android:width="0.5dp" android:color="#DAA520"/>
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
</layer-list>
|
||||||
22
android-app/app/src/main/res/drawable/bg_wish_tag_green.xml
Normal file
22
android-app/app/src/main/res/drawable/bg_wish_tag_green.xml
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<!-- 绳子 -->
|
||||||
|
<item
|
||||||
|
android:gravity="top|center_horizontal"
|
||||||
|
android:top="0dp"
|
||||||
|
android:left="12dp"
|
||||||
|
android:right="12dp">
|
||||||
|
<shape android:shape="rectangle">
|
||||||
|
<solid android:color="#A0522D"/>
|
||||||
|
<size android:width="2dp" android:height="12dp"/>
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
<!-- 许愿牌主体 -->
|
||||||
|
<item android:top="10dp">
|
||||||
|
<shape android:shape="rectangle">
|
||||||
|
<solid android:color="#98D982"/>
|
||||||
|
<corners android:radius="3dp"/>
|
||||||
|
<stroke android:width="0.5dp" android:color="#6BBF59"/>
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
</layer-list>
|
||||||
22
android-app/app/src/main/res/drawable/bg_wish_tag_orange.xml
Normal file
22
android-app/app/src/main/res/drawable/bg_wish_tag_orange.xml
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<!-- 绳子 -->
|
||||||
|
<item
|
||||||
|
android:gravity="top|center_horizontal"
|
||||||
|
android:top="0dp"
|
||||||
|
android:left="12dp"
|
||||||
|
android:right="12dp">
|
||||||
|
<shape android:shape="rectangle">
|
||||||
|
<solid android:color="#A0522D"/>
|
||||||
|
<size android:width="2dp" android:height="12dp"/>
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
<!-- 许愿牌主体 -->
|
||||||
|
<item android:top="10dp">
|
||||||
|
<shape android:shape="rectangle">
|
||||||
|
<solid android:color="#FFB347"/>
|
||||||
|
<corners android:radius="3dp"/>
|
||||||
|
<stroke android:width="0.5dp" android:color="#FF8C00"/>
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
</layer-list>
|
||||||
22
android-app/app/src/main/res/drawable/bg_wish_tag_pink.xml
Normal file
22
android-app/app/src/main/res/drawable/bg_wish_tag_pink.xml
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<!-- 绳子 -->
|
||||||
|
<item
|
||||||
|
android:gravity="top|center_horizontal"
|
||||||
|
android:top="0dp"
|
||||||
|
android:left="12dp"
|
||||||
|
android:right="12dp">
|
||||||
|
<shape android:shape="rectangle">
|
||||||
|
<solid android:color="#A0522D"/>
|
||||||
|
<size android:width="2dp" android:height="12dp"/>
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
<!-- 许愿牌主体 -->
|
||||||
|
<item android:top="10dp">
|
||||||
|
<shape android:shape="rectangle">
|
||||||
|
<solid android:color="#FFB6C1"/>
|
||||||
|
<corners android:radius="3dp"/>
|
||||||
|
<stroke android:width="0.5dp" android:color="#FF69B4"/>
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
</layer-list>
|
||||||
22
android-app/app/src/main/res/drawable/bg_wish_tag_purple.xml
Normal file
22
android-app/app/src/main/res/drawable/bg_wish_tag_purple.xml
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<!-- 绳子 -->
|
||||||
|
<item
|
||||||
|
android:gravity="top|center_horizontal"
|
||||||
|
android:top="0dp"
|
||||||
|
android:left="12dp"
|
||||||
|
android:right="12dp">
|
||||||
|
<shape android:shape="rectangle">
|
||||||
|
<solid android:color="#A0522D"/>
|
||||||
|
<size android:width="2dp" android:height="12dp"/>
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
<!-- 许愿牌主体 -->
|
||||||
|
<item android:top="10dp">
|
||||||
|
<shape android:shape="rectangle">
|
||||||
|
<solid android:color="#DDA0DD"/>
|
||||||
|
<corners android:radius="3dp"/>
|
||||||
|
<stroke android:width="0.5dp" android:color="#9370DB"/>
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
</layer-list>
|
||||||
22
android-app/app/src/main/res/drawable/bg_wish_tag_yellow.xml
Normal file
22
android-app/app/src/main/res/drawable/bg_wish_tag_yellow.xml
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<!-- 绳子 -->
|
||||||
|
<item
|
||||||
|
android:gravity="top|center_horizontal"
|
||||||
|
android:top="0dp"
|
||||||
|
android:left="12dp"
|
||||||
|
android:right="12dp">
|
||||||
|
<shape android:shape="rectangle">
|
||||||
|
<solid android:color="#A0522D"/>
|
||||||
|
<size android:width="2dp" android:height="12dp"/>
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
<!-- 许愿牌主体 -->
|
||||||
|
<item android:top="10dp">
|
||||||
|
<shape android:shape="rectangle">
|
||||||
|
<solid android:color="#F0E68C"/>
|
||||||
|
<corners android:radius="3dp"/>
|
||||||
|
<stroke android:width="0.5dp" android:color="#DAA520"/>
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
</layer-list>
|
||||||
10
android-app/app/src/main/res/drawable/ic_close_circle_24.xml
Normal file
10
android-app/app/src/main/res/drawable/ic_close_circle_24.xml
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FF4757"
|
||||||
|
android:pathData="M12,2C6.47,2 2,6.47 2,12s4.47,10 10,10 10,-4.47 10,-10S17.53,2 12,2zM17,15.59L15.59,17 12,13.41 8.41,17 7,15.59 10.59,12 7,8.41 8.41,7 12,10.59 15.59,7 17,8.41 13.41,12 17,15.59z"/>
|
||||||
|
</vector>
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 258 KiB After Width: | Height: | Size: 4.3 MiB |
|
|
@ -30,15 +30,15 @@
|
||||||
<com.google.android.material.bottomnavigation.BottomNavigationView
|
<com.google.android.material.bottomnavigation.BottomNavigationView
|
||||||
android:id="@+id/bottomNavigation"
|
android:id="@+id/bottomNavigation"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="48dp"
|
android:layout_height="56dp"
|
||||||
android:minHeight="48dp"
|
android:minHeight="56dp"
|
||||||
android:background="@android:color/white"
|
android:background="@android:color/white"
|
||||||
android:paddingTop="2dp"
|
android:paddingTop="2dp"
|
||||||
android:paddingBottom="2dp"
|
android:paddingBottom="2dp"
|
||||||
android:fitsSystemWindows="false"
|
android:fitsSystemWindows="false"
|
||||||
android:elevation="8dp"
|
android:elevation="8dp"
|
||||||
app:itemIconTint="@color/bottom_nav_item_color"
|
app:itemIconTint="@color/bottom_nav_icon_glow_color"
|
||||||
app:itemTextColor="@color/bottom_nav_item_color"
|
app:itemTextColor="@color/bottom_nav_icon_glow_color"
|
||||||
app:itemIconSize="22dp"
|
app:itemIconSize="22dp"
|
||||||
app:itemTextAppearanceActive="@style/BottomNavigationView.TextAppearance"
|
app:itemTextAppearanceActive="@style/BottomNavigationView.TextAppearance"
|
||||||
app:itemTextAppearanceInactive="@style/BottomNavigationView.TextAppearance"
|
app:itemTextAppearanceInactive="@style/BottomNavigationView.TextAppearance"
|
||||||
|
|
|
||||||
|
|
@ -57,4 +57,29 @@
|
||||||
android:paddingBottom="16dp"
|
android:paddingBottom="16dp"
|
||||||
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
|
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/emptyView"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:gravity="center"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:layout_behavior="@string/appbar_scrolling_view_behavior">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="64dp"
|
||||||
|
android:layout_height="64dp"
|
||||||
|
android:src="@drawable/ic_heart_24"
|
||||||
|
android:tint="#CCCCCC" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:text="暂无获赞记录"
|
||||||
|
android:textColor="#999999"
|
||||||
|
android:textSize="14sp" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||||
|
|
|
||||||
|
|
@ -39,10 +39,10 @@
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:background="@android:color/transparent"
|
android:background="@android:color/transparent"
|
||||||
app:tabIndicatorColor="#FF4757"
|
app:tabIndicatorColor="#A855F7"
|
||||||
app:tabIndicatorFullWidth="false"
|
app:tabIndicatorFullWidth="false"
|
||||||
app:tabIndicatorHeight="3dp"
|
app:tabIndicatorHeight="3dp"
|
||||||
app:tabSelectedTextColor="#333333"
|
app:tabSelectedTextColor="#A855F7"
|
||||||
app:tabTextColor="#999999"
|
app:tabTextColor="#999999"
|
||||||
app:tabRippleColor="@android:color/transparent"
|
app:tabRippleColor="@android:color/transparent"
|
||||||
app:tabTextAppearance="@style/TabTextAppearance"
|
app:tabTextAppearance="@style/TabTextAppearance"
|
||||||
|
|
@ -167,11 +167,11 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:paddingStart="8dp"
|
android:paddingStart="8dp"
|
||||||
app:tabIndicatorColor="#FF4757"
|
app:tabIndicatorColor="#A855F7"
|
||||||
app:tabIndicatorFullWidth="false"
|
app:tabIndicatorFullWidth="false"
|
||||||
app:tabMode="scrollable"
|
app:tabMode="scrollable"
|
||||||
app:tabGravity="start"
|
app:tabGravity="start"
|
||||||
app:tabSelectedTextColor="#333333"
|
app:tabSelectedTextColor="#A855F7"
|
||||||
app:tabTextColor="#999999">
|
app:tabTextColor="#999999">
|
||||||
|
|
||||||
<com.google.android.material.tabs.TabItem
|
<com.google.android.material.tabs.TabItem
|
||||||
|
|
|
||||||
|
|
@ -3,12 +3,12 @@
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:background="@color/deep_night_bg">
|
android:background="@color/white">
|
||||||
|
|
||||||
<com.google.android.material.appbar.AppBarLayout
|
<com.google.android.material.appbar.AppBarLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:background="@drawable/bg_appbar_glass"
|
android:background="@color/white"
|
||||||
app:elevation="0dp">
|
app:elevation="0dp">
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
|
@ -24,7 +24,7 @@
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="💬 消息"
|
android:text="💬 消息"
|
||||||
android:textColor="@color/white"
|
android:textColor="@color/black"
|
||||||
android:textSize="@dimen/text_title"
|
android:textSize="@dimen/text_title"
|
||||||
android:textStyle="bold"
|
android:textStyle="bold"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
|
@ -41,7 +41,7 @@
|
||||||
android:padding="6dp"
|
android:padding="6dp"
|
||||||
android:contentDescription="搜索"
|
android:contentDescription="搜索"
|
||||||
android:src="@drawable/ic_search_24"
|
android:src="@drawable/ic_search_24"
|
||||||
app:tint="@color/white"
|
app:tint="@color/black"
|
||||||
app:layout_constraintEnd_toStartOf="@id/addIcon"
|
app:layout_constraintEnd_toStartOf="@id/addIcon"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
app:layout_constraintBottom_toBottomOf="parent" />
|
app:layout_constraintBottom_toBottomOf="parent" />
|
||||||
|
|
@ -55,7 +55,7 @@
|
||||||
android:padding="6dp"
|
android:padding="6dp"
|
||||||
android:contentDescription="添加"
|
android:contentDescription="添加"
|
||||||
android:src="@drawable/ic_add_24"
|
android:src="@drawable/ic_add_24"
|
||||||
app:tint="@color/white"
|
app:tint="@color/black"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
app:layout_constraintBottom_toBottomOf="parent" />
|
app:layout_constraintBottom_toBottomOf="parent" />
|
||||||
|
|
|
||||||
|
|
@ -212,7 +212,7 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="0dp"
|
android:layout_marginStart="0dp"
|
||||||
android:layout_marginEnd="0dp"
|
android:layout_marginEnd="0dp"
|
||||||
android:layout_marginTop="-58dp"
|
android:layout_marginTop="-80dp"
|
||||||
android:background="@drawable/bg_white_16"
|
android:background="@drawable/bg_white_16"
|
||||||
android:padding="14dp"
|
android:padding="14dp"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
|
@ -224,7 +224,7 @@
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
android:visibility="gone"
|
android:paddingBottom="12dp"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent">
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
@ -265,7 +265,7 @@
|
||||||
android:id="@+id/bioText"
|
android:id="@+id/bioText"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="12dp"
|
android:layout_marginTop="0dp"
|
||||||
android:text="填写个人签名更容易获得关注,点击此处添加"
|
android:text="填写个人签名更容易获得关注,点击此处添加"
|
||||||
android:textColor="#999999"
|
android:textColor="#999999"
|
||||||
android:textSize="12sp"
|
android:textSize="12sp"
|
||||||
|
|
@ -340,19 +340,6 @@
|
||||||
android:textColor="#666666"
|
android:textColor="#666666"
|
||||||
android:textSize="11sp" />
|
android:textSize="11sp" />
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/tagPersonality"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="24dp"
|
|
||||||
android:layout_marginStart="8dp"
|
|
||||||
android:background="@drawable/bg_gray_12"
|
|
||||||
android:gravity="center"
|
|
||||||
android:paddingStart="10dp"
|
|
||||||
android:paddingEnd="10dp"
|
|
||||||
android:text="性格测试"
|
|
||||||
android:textColor="#666666"
|
|
||||||
android:textSize="11sp" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</HorizontalScrollView>
|
</HorizontalScrollView>
|
||||||
|
|
@ -366,215 +353,157 @@
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@id/tagScrollView">
|
app:layout_constraintTop_toBottomOf="@id/tagScrollView">
|
||||||
|
|
||||||
<HorizontalScrollView
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:scrollbars="none">
|
android:orientation="horizontal"
|
||||||
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="wrap_content"
|
android:id="@+id/action1"
|
||||||
android:layout_height="wrap_content"
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="56dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:gravity="center"
|
||||||
android:orientation="horizontal">
|
android:orientation="horizontal">
|
||||||
|
|
||||||
<LinearLayout
|
<FrameLayout
|
||||||
android:id="@+id/action1"
|
android:layout_width="36dp"
|
||||||
android:layout_width="wrap_content"
|
android:layout_height="36dp"
|
||||||
android:layout_height="64dp"
|
android:background="@drawable/bg_gray_12">
|
||||||
android:layout_marginEnd="16dp"
|
|
||||||
android:gravity="center_vertical"
|
|
||||||
android:orientation="horizontal">
|
|
||||||
|
|
||||||
<FrameLayout
|
<ImageView
|
||||||
android:layout_width="44dp"
|
android:layout_width="20dp"
|
||||||
android:layout_height="44dp"
|
android:layout_height="20dp"
|
||||||
android:background="@drawable/bg_gray_12">
|
android:layout_gravity="center"
|
||||||
|
android:src="@drawable/ic_person_add_24"
|
||||||
|
android:tint="@color/purple_500" />
|
||||||
|
|
||||||
<ImageView
|
</FrameLayout>
|
||||||
android:layout_width="24dp"
|
|
||||||
android:layout_height="24dp"
|
|
||||||
android:layout_gravity="center"
|
|
||||||
android:src="@drawable/ic_person_add_24"
|
|
||||||
android:tint="@color/purple_500" />
|
|
||||||
|
|
||||||
</FrameLayout>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="8dp"
|
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="我的关注"
|
|
||||||
android:textColor="#111111"
|
|
||||||
android:textSize="14sp"
|
|
||||||
android:textStyle="bold" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/followingCount"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="2dp"
|
|
||||||
android:text="0人"
|
|
||||||
android:textColor="#999999"
|
|
||||||
android:textSize="11sp" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/action2"
|
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="64dp"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginEnd="16dp"
|
android:layout_marginStart="6dp"
|
||||||
android:gravity="center_vertical"
|
android:orientation="vertical">
|
||||||
android:orientation="horizontal">
|
|
||||||
|
|
||||||
<FrameLayout
|
<TextView
|
||||||
android:layout_width="44dp"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="44dp"
|
android:layout_height="wrap_content"
|
||||||
android:background="@drawable/bg_gray_12">
|
android:text="我的关注"
|
||||||
|
android:textColor="#111111"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
|
||||||
<ImageView
|
<TextView
|
||||||
android:layout_width="24dp"
|
android:id="@+id/followingCount"
|
||||||
android:layout_height="24dp"
|
android:layout_width="wrap_content"
|
||||||
android:layout_gravity="center"
|
android:layout_height="wrap_content"
|
||||||
android:src="@drawable/ic_like_filled_24"
|
android:text="0人"
|
||||||
android:tint="#FF4081" />
|
android:textColor="#999999"
|
||||||
|
android:textSize="10sp" />
|
||||||
</FrameLayout>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="8dp"
|
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="我的点赞"
|
|
||||||
android:textColor="#111111"
|
|
||||||
android:textSize="14sp"
|
|
||||||
android:textStyle="bold" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/likedRoomsCount"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="2dp"
|
|
||||||
android:text="0个直播间"
|
|
||||||
android:textColor="#999999"
|
|
||||||
android:textSize="11sp" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/action3"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="64dp"
|
|
||||||
android:layout_marginEnd="16dp"
|
|
||||||
android:gravity="center_vertical"
|
|
||||||
android:orientation="horizontal">
|
|
||||||
|
|
||||||
<FrameLayout
|
|
||||||
android:layout_width="44dp"
|
|
||||||
android:layout_height="44dp"
|
|
||||||
android:background="@drawable/bg_gray_12">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:layout_width="24dp"
|
|
||||||
android:layout_height="24dp"
|
|
||||||
android:layout_gravity="center"
|
|
||||||
android:src="@drawable/ic_star_24"
|
|
||||||
android:tint="#FFA726" />
|
|
||||||
|
|
||||||
</FrameLayout>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="8dp"
|
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="我的收藏"
|
|
||||||
android:textColor="#111111"
|
|
||||||
android:textSize="14sp"
|
|
||||||
android:textStyle="bold" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/friendsCount"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="2dp"
|
|
||||||
android:text="0个"
|
|
||||||
android:textColor="#999999"
|
|
||||||
android:textSize="11sp" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/action4"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="64dp"
|
|
||||||
android:gravity="center_vertical"
|
|
||||||
android:orientation="horizontal"
|
|
||||||
android:visibility="gone">
|
|
||||||
|
|
||||||
<FrameLayout
|
|
||||||
android:layout_width="44dp"
|
|
||||||
android:layout_height="44dp"
|
|
||||||
android:background="@drawable/bg_gray_12">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:layout_width="24dp"
|
|
||||||
android:layout_height="24dp"
|
|
||||||
android:layout_gravity="center"
|
|
||||||
android:src="@drawable/ic_history_24"
|
|
||||||
android:tint="#2196F3" />
|
|
||||||
|
|
||||||
</FrameLayout>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="8dp"
|
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="我的记录"
|
|
||||||
android:textColor="#111111"
|
|
||||||
android:textSize="14sp"
|
|
||||||
android:textStyle="bold" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/recordsCount"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="2dp"
|
|
||||||
android:text="查看全部"
|
|
||||||
android:textColor="#999999"
|
|
||||||
android:textSize="11sp" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</HorizontalScrollView>
|
<LinearLayout
|
||||||
|
android:id="@+id/action2"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="56dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:gravity="center"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:layout_width="36dp"
|
||||||
|
android:layout_height="36dp"
|
||||||
|
android:background="@drawable/bg_gray_12">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="20dp"
|
||||||
|
android:layout_height="20dp"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:src="@drawable/ic_people_24"
|
||||||
|
android:tint="#4CAF50" />
|
||||||
|
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="6dp"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="我的好友"
|
||||||
|
android:textColor="#111111"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/friendsCount"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="0人"
|
||||||
|
android:textColor="#999999"
|
||||||
|
android:textSize="10sp" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/action3"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="56dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:gravity="center"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:layout_width="36dp"
|
||||||
|
android:layout_height="36dp"
|
||||||
|
android:background="@drawable/bg_gray_12">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="20dp"
|
||||||
|
android:layout_height="20dp"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:src="@drawable/ic_star_24"
|
||||||
|
android:tint="#FFA726" />
|
||||||
|
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="6dp"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="我的收藏"
|
||||||
|
android:textColor="#111111"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/collectionsCount"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="0个"
|
||||||
|
android:textColor="#999999"
|
||||||
|
android:textSize="10sp" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
|
@ -701,7 +630,7 @@
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@id/walletButton">
|
app:layout_constraintTop_toBottomOf="@id/walletButton">
|
||||||
|
|
||||||
<!-- 标题栏 -->
|
<!-- Tab切换栏 -->
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
|
@ -710,13 +639,36 @@
|
||||||
android:paddingBottom="12dp">
|
android:paddingBottom="12dp">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="0dp"
|
android:id="@+id/tabWorks"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="1"
|
android:text="作品"
|
||||||
android:text="我的作品"
|
|
||||||
android:textColor="#111111"
|
android:textColor="#111111"
|
||||||
android:textSize="16sp"
|
android:textSize="16sp"
|
||||||
android:textStyle="bold" />
|
android:textStyle="bold"
|
||||||
|
android:paddingEnd="16dp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tabLiked"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="赞过"
|
||||||
|
android:textColor="#999999"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:paddingEnd="16dp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tabCollected"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="收藏"
|
||||||
|
android:textColor="#999999"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_weight="1" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/myWorksCount"
|
android:id="@+id/myWorksCount"
|
||||||
|
|
@ -736,6 +688,22 @@
|
||||||
android:nestedScrollingEnabled="false"
|
android:nestedScrollingEnabled="false"
|
||||||
android:visibility="gone" />
|
android:visibility="gone" />
|
||||||
|
|
||||||
|
<!-- 赞过列表 -->
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/likedWorksRecycler"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:nestedScrollingEnabled="false"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
|
<!-- 收藏列表 -->
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/collectedWorksRecycler"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:nestedScrollingEnabled="false"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
<!-- 空状态 -->
|
<!-- 空状态 -->
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/myWorksEmptyState"
|
android:id="@+id/myWorksEmptyState"
|
||||||
|
|
@ -746,6 +714,7 @@
|
||||||
android:visibility="visible">
|
android:visibility="visible">
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
|
android:id="@+id/emptyStateIcon"
|
||||||
android:layout_width="56dp"
|
android:layout_width="56dp"
|
||||||
android:layout_height="56dp"
|
android:layout_height="56dp"
|
||||||
android:alpha="0.5"
|
android:alpha="0.5"
|
||||||
|
|
@ -753,6 +722,7 @@
|
||||||
android:tint="#999999" />
|
android:tint="#999999" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
|
android:id="@+id/emptyStateText"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="12dp"
|
android:layout_marginTop="12dp"
|
||||||
|
|
@ -819,7 +789,7 @@
|
||||||
app:layout_constraintTop_toBottomOf="@id/profileTabs">
|
app:layout_constraintTop_toBottomOf="@id/profileTabs">
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:id="@+id/tabWorks"
|
android:id="@+id/tabWorksContent"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content">
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
|
@ -882,7 +852,7 @@
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:id="@+id/tabLiked"
|
android:id="@+id/tabLikedContent"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="320dp"
|
android:layout_height="320dp"
|
||||||
android:visibility="gone">
|
android:visibility="gone">
|
||||||
|
|
|
||||||
494
android-app/app/src/main/res/layout/activity_publish_center.xml
Normal file
494
android-app/app/src/main/res/layout/activity_publish_center.xml
Normal file
|
|
@ -0,0 +1,494 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="@color/white">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/topBar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="56dp"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:paddingHorizontal="16dp"
|
||||||
|
android:background="@color/white"
|
||||||
|
android:elevation="2dp">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/btnBack"
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:src="@drawable/ic_close_24"
|
||||||
|
android:contentDescription="关闭"
|
||||||
|
app:tint="#333333" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:text="发布"
|
||||||
|
android:textSize="18sp"
|
||||||
|
android:textColor="#333333"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<com.google.android.material.tabs.TabLayout
|
||||||
|
android:id="@+id/tabLayout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="48dp"
|
||||||
|
android:layout_marginTop="56dp"
|
||||||
|
android:background="@color/white"
|
||||||
|
app:tabMode="fixed"
|
||||||
|
app:tabGravity="fill"
|
||||||
|
app:tabIndicatorColor="#FF4757"
|
||||||
|
app:tabIndicatorHeight="3dp"
|
||||||
|
app:tabSelectedTextColor="#FF4757"
|
||||||
|
app:tabTextColor="#666666"
|
||||||
|
app:tabRippleColor="@android:color/transparent">
|
||||||
|
|
||||||
|
<com.google.android.material.tabs.TabItem
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="手机开播" />
|
||||||
|
|
||||||
|
<com.google.android.material.tabs.TabItem
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="发布动态" />
|
||||||
|
|
||||||
|
<com.google.android.material.tabs.TabItem
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="发布作品" />
|
||||||
|
|
||||||
|
<com.google.android.material.tabs.TabItem
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="电脑开播" />
|
||||||
|
|
||||||
|
</com.google.android.material.tabs.TabLayout>
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_marginTop="104dp">
|
||||||
|
|
||||||
|
<!-- 手机开播 -->
|
||||||
|
<ScrollView
|
||||||
|
android:id="@+id/contentMobileLive"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:visibility="visible">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="20dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="手机开播"
|
||||||
|
android:textSize="20sp"
|
||||||
|
android:textColor="#333333"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:text="使用手机摄像头进行直播"
|
||||||
|
android:textSize="14sp"
|
||||||
|
android:textColor="#999999" />
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="24dp"
|
||||||
|
android:hint="直播标题"
|
||||||
|
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:id="@+id/etLiveTitle"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:inputType="text"
|
||||||
|
android:maxLength="30" />
|
||||||
|
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btnStartLive"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="52dp"
|
||||||
|
android:layout_marginTop="32dp"
|
||||||
|
android:text="开始直播"
|
||||||
|
android:textSize="16sp"
|
||||||
|
app:backgroundTint="#FF4757"
|
||||||
|
app:cornerRadius="26dp" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</ScrollView>
|
||||||
|
|
||||||
|
<!-- 发布动态 -->
|
||||||
|
<ScrollView
|
||||||
|
android:id="@+id/contentDynamic"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:visibility="gone">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="20dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="发布动态"
|
||||||
|
android:textSize="20sp"
|
||||||
|
android:textColor="#333333"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:text="快速发布文字动态,可选择添加封面图片"
|
||||||
|
android:textSize="14sp"
|
||||||
|
android:textColor="#999999" />
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="24dp"
|
||||||
|
android:hint="说点什么..."
|
||||||
|
app:counterEnabled="true"
|
||||||
|
app:counterMaxLength="1000"
|
||||||
|
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:id="@+id/etDynamicContent"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:inputType="textMultiLine"
|
||||||
|
android:minLines="5"
|
||||||
|
android:gravity="top"
|
||||||
|
android:maxLength="1000" />
|
||||||
|
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
<!-- 封面图片选择(可选) -->
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="20dp"
|
||||||
|
android:text="封面图片(可选)"
|
||||||
|
android:textSize="14sp"
|
||||||
|
android:textColor="#666666" />
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/dynamicCoverContainer"
|
||||||
|
android:layout_width="120dp"
|
||||||
|
android:layout_height="120dp"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:background="@drawable/bg_dashed_border"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/ivDynamicCover"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:scaleType="centerCrop"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/dynamicCoverPlaceholder"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:gravity="center">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="32dp"
|
||||||
|
android:layout_height="32dp"
|
||||||
|
android:src="@drawable/ic_add_photo_24"
|
||||||
|
app:tint="#999999" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="4dp"
|
||||||
|
android:text="添加封面"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:textColor="#999999" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/btnRemoveDynamicCover"
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:layout_gravity="top|end"
|
||||||
|
android:layout_margin="4dp"
|
||||||
|
android:src="@drawable/ic_close_circle_24"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:contentDescription="移除封面" />
|
||||||
|
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btnPublishDynamic"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="52dp"
|
||||||
|
android:layout_marginTop="32dp"
|
||||||
|
android:text="发布动态"
|
||||||
|
android:textSize="16sp"
|
||||||
|
app:backgroundTint="#FF4757"
|
||||||
|
app:cornerRadius="26dp" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</ScrollView>
|
||||||
|
|
||||||
|
<!-- 发布作品 -->
|
||||||
|
<ScrollView
|
||||||
|
android:id="@+id/contentWork"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:visibility="gone">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="20dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="发布作品"
|
||||||
|
android:textSize="20sp"
|
||||||
|
android:textColor="#333333"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:text="发布图片或视频作品,支持添加标题、描述等"
|
||||||
|
android:textSize="14sp"
|
||||||
|
android:textColor="#999999" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btnPublishWork"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="52dp"
|
||||||
|
android:layout_marginTop="32dp"
|
||||||
|
android:text="去发布作品"
|
||||||
|
android:textSize="16sp"
|
||||||
|
app:backgroundTint="#FF4757"
|
||||||
|
app:cornerRadius="26dp" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</ScrollView>
|
||||||
|
|
||||||
|
<!-- 电脑开播 -->
|
||||||
|
<ScrollView
|
||||||
|
android:id="@+id/contentPcLive"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:visibility="gone">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="20dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="电脑开播"
|
||||||
|
android:textSize="20sp"
|
||||||
|
android:textColor="#333333"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:text="使用OBS等推流软件进行直播"
|
||||||
|
android:textSize="14sp"
|
||||||
|
android:textColor="#999999" />
|
||||||
|
|
||||||
|
<!-- 直播标题 -->
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="24dp"
|
||||||
|
android:hint="直播标题"
|
||||||
|
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:id="@+id/etPcLiveTitle"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:inputType="text"
|
||||||
|
android:maxLength="30" />
|
||||||
|
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
<!-- 分类选择 -->
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:text="选择分类"
|
||||||
|
android:textSize="14sp"
|
||||||
|
android:textColor="#666666" />
|
||||||
|
|
||||||
|
<Spinner
|
||||||
|
android:id="@+id/spinnerPcCategory"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="48dp"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:background="@drawable/bg_spinner"
|
||||||
|
android:paddingHorizontal="12dp" />
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/streamInfoLoading"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:layout_marginTop="24dp"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/streamInfoContent"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_marginTop="24dp"
|
||||||
|
android:visibility="gone">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="推流地址"
|
||||||
|
android:textSize="14sp"
|
||||||
|
android:textColor="#666666" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:background="@drawable/bg_edit_text"
|
||||||
|
android:padding="12dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvStreamUrl"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text=""
|
||||||
|
android:textSize="13sp"
|
||||||
|
android:textColor="#333333"
|
||||||
|
android:maxLines="2"
|
||||||
|
android:ellipsize="end" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/btnCopyStreamUrl"
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:src="@drawable/ic_copy_24"
|
||||||
|
android:contentDescription="复制"
|
||||||
|
app:tint="#666666" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:text="推流码"
|
||||||
|
android:textSize="14sp"
|
||||||
|
android:textColor="#666666" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:background="@drawable/bg_edit_text"
|
||||||
|
android:padding="12dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvStreamKey"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text=""
|
||||||
|
android:textSize="13sp"
|
||||||
|
android:textColor="#333333"
|
||||||
|
android:maxLines="2"
|
||||||
|
android:ellipsize="end" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/btnCopyStreamKey"
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:src="@drawable/ic_copy_24"
|
||||||
|
android:contentDescription="复制"
|
||||||
|
app:tint="#666666" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/btnGetStreamInfo"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="48dp"
|
||||||
|
android:layout_marginTop="24dp"
|
||||||
|
android:text="创建直播间并获取推流信息"
|
||||||
|
android:textSize="14sp"
|
||||||
|
app:backgroundTint="#FF4757"
|
||||||
|
app:cornerRadius="24dp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="24dp"
|
||||||
|
android:text="使用说明"
|
||||||
|
android:textSize="14sp"
|
||||||
|
android:textColor="#333333"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:text="1. 填写直播标题并选择分类\n2. 点击按钮创建直播间获取推流信息\n3. 下载并安装OBS Studio\n4. 打开OBS,点击设置 - 推流\n5. 服务选择自定义\n6. 将上方的推流地址和推流码填入\n7. 点击开始推流即可"
|
||||||
|
android:textSize="13sp"
|
||||||
|
android:textColor="#666666"
|
||||||
|
android:lineSpacingExtra="4dp" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</ScrollView>
|
||||||
|
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||||
|
|
@ -1,442 +1,362 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent">
|
||||||
android:background="@drawable/bg_deep_night_gradient">
|
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<FrameLayout
|
||||||
android:id="@+id/content"
|
android:id="@+id/rootContainer"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:paddingBottom="60dp">
|
android:paddingBottom="56dp">
|
||||||
|
|
||||||
|
<!-- 许愿树背景图 -->
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/wishTreeImage"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:contentDescription="Wish Tree"
|
||||||
|
android:scaleType="centerCrop"
|
||||||
|
android:src="@drawable/wish_tree" />
|
||||||
|
|
||||||
|
<!-- 心愿牌容器 -->
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/wishTagsContainer"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<!-- 心愿牌1 - 左上树枝 -->
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/wishTag1"
|
||||||
|
android:layout_width="26dp"
|
||||||
|
android:layout_height="68dp"
|
||||||
|
android:layout_marginStart="55dp"
|
||||||
|
android:layout_marginTop="200dp"
|
||||||
|
android:background="@drawable/bg_wish_tag_pink"
|
||||||
|
android:gravity="center_horizontal"
|
||||||
|
android:paddingTop="14dp"
|
||||||
|
android:paddingHorizontal="2dp"
|
||||||
|
android:text=""
|
||||||
|
android:textColor="#5D4037"
|
||||||
|
android:textSize="7sp"
|
||||||
|
android:lineSpacingExtra="-2dp"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:elevation="2dp" />
|
||||||
|
|
||||||
|
<!-- 心愿牌2 - 左侧中树枝 -->
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/wishTag2"
|
||||||
|
android:layout_width="26dp"
|
||||||
|
android:layout_height="68dp"
|
||||||
|
android:layout_marginStart="95dp"
|
||||||
|
android:layout_marginTop="230dp"
|
||||||
|
android:background="@drawable/bg_wish_tag_green"
|
||||||
|
android:gravity="center_horizontal"
|
||||||
|
android:paddingTop="14dp"
|
||||||
|
android:paddingHorizontal="2dp"
|
||||||
|
android:text=""
|
||||||
|
android:textColor="#5D4037"
|
||||||
|
android:textSize="7sp"
|
||||||
|
android:lineSpacingExtra="-2dp"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:elevation="2dp" />
|
||||||
|
|
||||||
|
<!-- 心愿牌3 - 中间偏左树枝 -->
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/wishTag3"
|
||||||
|
android:layout_width="26dp"
|
||||||
|
android:layout_height="68dp"
|
||||||
|
android:layout_marginStart="150dp"
|
||||||
|
android:layout_marginTop="195dp"
|
||||||
|
android:background="@drawable/bg_wish_tag_gold"
|
||||||
|
android:gravity="center_horizontal"
|
||||||
|
android:paddingTop="14dp"
|
||||||
|
android:paddingHorizontal="2dp"
|
||||||
|
android:text=""
|
||||||
|
android:textColor="#5D4037"
|
||||||
|
android:textSize="7sp"
|
||||||
|
android:lineSpacingExtra="-2dp"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:elevation="2dp" />
|
||||||
|
|
||||||
|
<!-- 心愿牌4 - 中间偏右树枝 -->
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/wishTag4"
|
||||||
|
android:layout_width="26dp"
|
||||||
|
android:layout_height="68dp"
|
||||||
|
android:layout_marginStart="210dp"
|
||||||
|
android:layout_marginTop="210dp"
|
||||||
|
android:background="@drawable/bg_wish_tag_blue"
|
||||||
|
android:gravity="center_horizontal"
|
||||||
|
android:paddingTop="14dp"
|
||||||
|
android:paddingHorizontal="2dp"
|
||||||
|
android:text=""
|
||||||
|
android:textColor="#5D4037"
|
||||||
|
android:textSize="7sp"
|
||||||
|
android:lineSpacingExtra="-2dp"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:elevation="2dp" />
|
||||||
|
|
||||||
|
<!-- 心愿牌5 - 右上树枝 -->
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/wishTag5"
|
||||||
|
android:layout_width="26dp"
|
||||||
|
android:layout_height="68dp"
|
||||||
|
android:layout_marginStart="280dp"
|
||||||
|
android:layout_marginTop="195dp"
|
||||||
|
android:background="@drawable/bg_wish_tag_purple"
|
||||||
|
android:gravity="center_horizontal"
|
||||||
|
android:paddingTop="14dp"
|
||||||
|
android:paddingHorizontal="2dp"
|
||||||
|
android:text=""
|
||||||
|
android:textColor="#5D4037"
|
||||||
|
android:textSize="7sp"
|
||||||
|
android:lineSpacingExtra="-2dp"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:elevation="2dp" />
|
||||||
|
|
||||||
|
<!-- 心愿牌6 - 右侧树枝末端 -->
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/wishTag6"
|
||||||
|
android:layout_width="26dp"
|
||||||
|
android:layout_height="68dp"
|
||||||
|
android:layout_marginStart="330dp"
|
||||||
|
android:layout_marginTop="320dp"
|
||||||
|
android:background="@drawable/bg_wish_tag_yellow"
|
||||||
|
android:gravity="center_horizontal"
|
||||||
|
android:paddingTop="14dp"
|
||||||
|
android:paddingHorizontal="2dp"
|
||||||
|
android:text=""
|
||||||
|
android:textColor="#5D4037"
|
||||||
|
android:textSize="7sp"
|
||||||
|
android:lineSpacingExtra="-2dp"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:elevation="2dp" />
|
||||||
|
|
||||||
|
<!-- 心愿牌7 - 左下树枝 -->
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/wishTag7"
|
||||||
|
android:layout_width="26dp"
|
||||||
|
android:layout_height="68dp"
|
||||||
|
android:layout_marginStart="25dp"
|
||||||
|
android:layout_marginTop="320dp"
|
||||||
|
android:background="@drawable/bg_wish_tag_orange"
|
||||||
|
android:gravity="center_horizontal"
|
||||||
|
android:paddingTop="14dp"
|
||||||
|
android:paddingHorizontal="2dp"
|
||||||
|
android:text=""
|
||||||
|
android:textColor="#5D4037"
|
||||||
|
android:textSize="7sp"
|
||||||
|
android:lineSpacingExtra="-2dp"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:elevation="2dp" />
|
||||||
|
|
||||||
|
<!-- 心愿牌8 - 左下中树枝 -->
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/wishTag8"
|
||||||
|
android:layout_width="26dp"
|
||||||
|
android:layout_height="68dp"
|
||||||
|
android:layout_marginStart="75dp"
|
||||||
|
android:layout_marginTop="290dp"
|
||||||
|
android:background="@drawable/bg_wish_tag_green"
|
||||||
|
android:gravity="center_horizontal"
|
||||||
|
android:paddingTop="14dp"
|
||||||
|
android:paddingHorizontal="2dp"
|
||||||
|
android:text=""
|
||||||
|
android:textColor="#5D4037"
|
||||||
|
android:textSize="7sp"
|
||||||
|
android:lineSpacingExtra="-2dp"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:elevation="2dp" />
|
||||||
|
|
||||||
|
<!-- 心愿牌9 - 中下树枝 -->
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/wishTag9"
|
||||||
|
android:layout_width="26dp"
|
||||||
|
android:layout_height="68dp"
|
||||||
|
android:layout_marginStart="130dp"
|
||||||
|
android:layout_marginTop="310dp"
|
||||||
|
android:background="@drawable/bg_wish_tag_blue"
|
||||||
|
android:gravity="center_horizontal"
|
||||||
|
android:paddingTop="14dp"
|
||||||
|
android:paddingHorizontal="2dp"
|
||||||
|
android:text=""
|
||||||
|
android:textColor="#5D4037"
|
||||||
|
android:textSize="7sp"
|
||||||
|
android:lineSpacingExtra="-2dp"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:elevation="2dp" />
|
||||||
|
|
||||||
|
<!-- 心愿牌10 - 右下树枝 -->
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/wishTag10"
|
||||||
|
android:layout_width="26dp"
|
||||||
|
android:layout_height="68dp"
|
||||||
|
android:layout_marginStart="240dp"
|
||||||
|
android:layout_marginTop="300dp"
|
||||||
|
android:background="@drawable/bg_wish_tag_pink"
|
||||||
|
android:gravity="center_horizontal"
|
||||||
|
android:paddingTop="14dp"
|
||||||
|
android:paddingHorizontal="2dp"
|
||||||
|
android:text=""
|
||||||
|
android:textColor="#5D4037"
|
||||||
|
android:textSize="7sp"
|
||||||
|
android:lineSpacingExtra="-2dp"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:elevation="2dp" />
|
||||||
|
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
<!-- 顶部栏 -->
|
<!-- 顶部栏 -->
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<LinearLayout
|
||||||
android:id="@+id/topBar"
|
android:id="@+id/topBar"
|
||||||
android:layout_width="0dp"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:paddingHorizontal="@dimen/page_margin"
|
android:orientation="horizontal"
|
||||||
android:paddingTop="@dimen/card_padding"
|
android:gravity="center_vertical"
|
||||||
android:paddingBottom="@dimen/spacing_sm"
|
android:paddingHorizontal="16dp"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
android:paddingTop="8dp"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
android:paddingBottom="4dp">
|
||||||
app:layout_constraintTop_toTopOf="parent">
|
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/title"
|
android:id="@+id/title"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="28dp"
|
android:layout_height="24dp"
|
||||||
|
android:layout_weight="1"
|
||||||
android:adjustViewBounds="true"
|
android:adjustViewBounds="true"
|
||||||
android:contentDescription="WishTree"
|
android:contentDescription="WishTree"
|
||||||
android:scaleType="fitStart"
|
android:scaleType="fitStart"
|
||||||
android:src="@drawable/wish_tree_title"
|
android:src="@drawable/wish_tree_title" />
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toStartOf="@id/searchButton"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
|
||||||
|
|
||||||
<ImageButton
|
<ImageButton
|
||||||
android:id="@+id/searchButton"
|
android:id="@+id/searchButton"
|
||||||
android:layout_width="40dp"
|
android:layout_width="36dp"
|
||||||
android:layout_height="40dp"
|
android:layout_height="36dp"
|
||||||
android:background="@drawable/bg_glass_button"
|
android:background="@drawable/bg_glass_button"
|
||||||
android:contentDescription="Search"
|
android:contentDescription="Search"
|
||||||
android:padding="@dimen/spacing_sm"
|
android:padding="6dp"
|
||||||
android:src="@drawable/ic_search_24"
|
android:src="@drawable/ic_search_24"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toStartOf="@id/notifyButton"
|
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
|
||||||
app:tint="@color/white" />
|
app:tint="@color/white" />
|
||||||
|
|
||||||
<ImageButton
|
<ImageButton
|
||||||
android:id="@+id/notifyButton"
|
android:id="@+id/notifyButton"
|
||||||
android:layout_width="40dp"
|
android:layout_width="36dp"
|
||||||
android:layout_height="40dp"
|
android:layout_height="36dp"
|
||||||
android:layout_marginStart="@dimen/spacing_sm"
|
android:layout_marginStart="8dp"
|
||||||
android:background="@drawable/bg_glass_button"
|
android:background="@drawable/bg_glass_button"
|
||||||
android:contentDescription="Notifications"
|
android:contentDescription="Notifications"
|
||||||
android:padding="@dimen/spacing_sm"
|
android:padding="6dp"
|
||||||
android:src="@drawable/ic_notifications_24"
|
android:src="@drawable/ic_notifications_24"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
|
||||||
app:tint="@color/white" />
|
app:tint="@color/white" />
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<!-- 活动横幅 - 玻璃拟态 -->
|
<!-- 活动横幅 -->
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<LinearLayout
|
||||||
android:id="@+id/banner"
|
android:id="@+id/banner"
|
||||||
android:layout_width="0dp"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginHorizontal="@dimen/page_margin"
|
android:layout_marginHorizontal="12dp"
|
||||||
|
android:layout_marginTop="48dp"
|
||||||
android:background="@drawable/bg_banner_glass"
|
android:background="@drawable/bg_banner_glass"
|
||||||
android:paddingHorizontal="@dimen/card_padding"
|
android:gravity="center_vertical"
|
||||||
android:paddingVertical="@dimen/spacing_sm"
|
android:orientation="horizontal"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
android:paddingHorizontal="10dp"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
android:paddingVertical="6dp">
|
||||||
app:layout_constraintTop_toBottomOf="@id/topBar">
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/bannerText"
|
android:id="@+id/bannerText"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
android:ellipsize="end"
|
android:ellipsize="end"
|
||||||
android:maxLines="1"
|
android:maxLines="1"
|
||||||
android:text="✨ 元旦许愿树 | 任意充值即翻倍"
|
android:text="✨ 许愿树 | 许下心愿,愿望成真"
|
||||||
android:textColor="@color/white"
|
android:textColor="@color/white"
|
||||||
android:textSize="@dimen/text_md"
|
android:textSize="12sp"
|
||||||
android:textStyle="bold"
|
android:textStyle="bold" />
|
||||||
android:shadowColor="#80000000"
|
|
||||||
android:shadowDx="1"
|
|
||||||
android:shadowDy="1"
|
|
||||||
android:shadowRadius="2"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toStartOf="@id/bannerTimer"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/bannerTimer"
|
android:id="@+id/bannerTimer"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:background="@drawable/bg_timer_pill"
|
android:background="@drawable/bg_timer_pill"
|
||||||
android:paddingHorizontal="@dimen/spacing_md"
|
android:paddingHorizontal="8dp"
|
||||||
android:paddingVertical="@dimen/spacing_xs"
|
android:paddingVertical="3dp"
|
||||||
android:text="12:30:05"
|
android:text="12:30:05"
|
||||||
android:textColor="@color/white"
|
android:textColor="@color/white"
|
||||||
android:textSize="@dimen/text_sm"
|
android:textSize="11sp"
|
||||||
android:textStyle="bold"
|
android:textStyle="bold" />
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<!-- 树形光晕效果 -->
|
<!-- 底部区域 -->
|
||||||
<View
|
<LinearLayout
|
||||||
android:id="@+id/treeGlow"
|
|
||||||
android:layout_width="400dp"
|
|
||||||
android:layout_height="400dp"
|
|
||||||
android:background="@drawable/bg_tree_glow_radial"
|
|
||||||
app:layout_constraintBottom_toTopOf="@id/bottomArea"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/banner"
|
|
||||||
app:layout_constraintVertical_bias="0.4" />
|
|
||||||
|
|
||||||
<!-- 许愿树背景图 -->
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/wishTreeImage"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="0dp"
|
|
||||||
android:clickable="false"
|
|
||||||
android:focusable="false"
|
|
||||||
android:contentDescription="Wish Tree"
|
|
||||||
android:scaleType="centerCrop"
|
|
||||||
android:src="@drawable/wish_tree"
|
|
||||||
app:layout_constraintBottom_toTopOf="@id/bottomArea"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/banner" />
|
|
||||||
|
|
||||||
<!-- 心愿卡片1 - 左上 -->
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/wishCard1"
|
|
||||||
android:layout_width="54dp"
|
|
||||||
android:layout_height="70dp"
|
|
||||||
android:background="@drawable/bg_wish_card_glass"
|
|
||||||
android:clickable="true"
|
|
||||||
android:focusable="true"
|
|
||||||
android:elevation="6dp"
|
|
||||||
android:gravity="center"
|
|
||||||
android:padding="@dimen/spacing_xs"
|
|
||||||
android:text=""
|
|
||||||
android:textColor="@color/white"
|
|
||||||
android:textSize="@dimen/text_xs"
|
|
||||||
android:shadowColor="#80000000"
|
|
||||||
android:shadowDx="1"
|
|
||||||
android:shadowDy="1"
|
|
||||||
android:shadowRadius="2"
|
|
||||||
app:layout_constraintHorizontal_bias="0.12"
|
|
||||||
app:layout_constraintVertical_bias="0.15"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/banner"
|
|
||||||
app:layout_constraintBottom_toTopOf="@id/bottomArea" />
|
|
||||||
|
|
||||||
<!-- 心愿卡片2 - 左中上 -->
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/wishCard2"
|
|
||||||
android:layout_width="60dp"
|
|
||||||
android:layout_height="78dp"
|
|
||||||
android:background="@drawable/bg_wish_card_glass"
|
|
||||||
android:clickable="true"
|
|
||||||
android:focusable="true"
|
|
||||||
android:elevation="6dp"
|
|
||||||
android:gravity="center"
|
|
||||||
android:padding="@dimen/spacing_xs"
|
|
||||||
android:text=""
|
|
||||||
android:textColor="@color/white"
|
|
||||||
android:textSize="@dimen/text_sm"
|
|
||||||
android:shadowColor="#80000000"
|
|
||||||
android:shadowDx="1"
|
|
||||||
android:shadowDy="1"
|
|
||||||
android:shadowRadius="2"
|
|
||||||
app:layout_constraintHorizontal_bias="0.32"
|
|
||||||
app:layout_constraintVertical_bias="0.08"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/banner"
|
|
||||||
app:layout_constraintBottom_toTopOf="@id/bottomArea" />
|
|
||||||
|
|
||||||
<!-- 心愿卡片3 - 右上 -->
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/wishCard3"
|
|
||||||
android:layout_width="54dp"
|
|
||||||
android:layout_height="70dp"
|
|
||||||
android:background="@drawable/bg_wish_card_glass"
|
|
||||||
android:clickable="true"
|
|
||||||
android:focusable="true"
|
|
||||||
android:elevation="6dp"
|
|
||||||
android:gravity="center"
|
|
||||||
android:padding="@dimen/spacing_xs"
|
|
||||||
android:text=""
|
|
||||||
android:textColor="@color/white"
|
|
||||||
android:textSize="@dimen/text_xs"
|
|
||||||
android:shadowColor="#80000000"
|
|
||||||
android:shadowDx="1"
|
|
||||||
android:shadowDy="1"
|
|
||||||
android:shadowRadius="2"
|
|
||||||
app:layout_constraintHorizontal_bias="0.88"
|
|
||||||
app:layout_constraintVertical_bias="0.12"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/banner"
|
|
||||||
app:layout_constraintBottom_toTopOf="@id/bottomArea" />
|
|
||||||
|
|
||||||
<!-- 心愿卡片4 - 左中 -->
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/wishCard4"
|
|
||||||
android:layout_width="60dp"
|
|
||||||
android:layout_height="78dp"
|
|
||||||
android:background="@drawable/bg_wish_card_glass"
|
|
||||||
android:clickable="true"
|
|
||||||
android:focusable="true"
|
|
||||||
android:elevation="6dp"
|
|
||||||
android:gravity="center"
|
|
||||||
android:padding="@dimen/spacing_xs"
|
|
||||||
android:text=""
|
|
||||||
android:textColor="@color/white"
|
|
||||||
android:textSize="@dimen/text_sm"
|
|
||||||
android:shadowColor="#80000000"
|
|
||||||
android:shadowDx="1"
|
|
||||||
android:shadowDy="1"
|
|
||||||
android:shadowRadius="2"
|
|
||||||
app:layout_constraintHorizontal_bias="0.05"
|
|
||||||
app:layout_constraintVertical_bias="0.38"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/banner"
|
|
||||||
app:layout_constraintBottom_toTopOf="@id/bottomArea" />
|
|
||||||
|
|
||||||
<!-- 添加心愿按钮 - 中央偏右 -->
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/addWishCard"
|
|
||||||
android:layout_width="66dp"
|
|
||||||
android:layout_height="85dp"
|
|
||||||
android:background="@drawable/bg_wish_card_add_glass"
|
|
||||||
android:clickable="true"
|
|
||||||
android:focusable="true"
|
|
||||||
android:elevation="8dp"
|
|
||||||
android:gravity="center"
|
|
||||||
android:padding="@dimen/spacing_xs"
|
|
||||||
android:text="心愿\n✦"
|
|
||||||
android:textColor="@color/shimmer_gold"
|
|
||||||
android:textSize="@dimen/text_md"
|
|
||||||
android:textStyle="bold"
|
|
||||||
android:shadowColor="#80000000"
|
|
||||||
android:shadowDx="1"
|
|
||||||
android:shadowDy="1"
|
|
||||||
android:shadowRadius="3"
|
|
||||||
app:layout_constraintHorizontal_bias="0.72"
|
|
||||||
app:layout_constraintVertical_bias="0.32"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/banner"
|
|
||||||
app:layout_constraintBottom_toTopOf="@id/bottomArea" />
|
|
||||||
|
|
||||||
<!-- 心愿卡片5 - 右中 -->
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/wishCard5"
|
|
||||||
android:layout_width="54dp"
|
|
||||||
android:layout_height="70dp"
|
|
||||||
android:background="@drawable/bg_wish_card_glass"
|
|
||||||
android:clickable="true"
|
|
||||||
android:focusable="true"
|
|
||||||
android:elevation="6dp"
|
|
||||||
android:gravity="center"
|
|
||||||
android:padding="@dimen/spacing_xs"
|
|
||||||
android:text=""
|
|
||||||
android:textColor="@color/white"
|
|
||||||
android:textSize="@dimen/text_xs"
|
|
||||||
android:shadowColor="#80000000"
|
|
||||||
android:shadowDx="1"
|
|
||||||
android:shadowDy="1"
|
|
||||||
android:shadowRadius="2"
|
|
||||||
app:layout_constraintHorizontal_bias="0.92"
|
|
||||||
app:layout_constraintVertical_bias="0.42"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/banner"
|
|
||||||
app:layout_constraintBottom_toTopOf="@id/bottomArea" />
|
|
||||||
|
|
||||||
<!-- 心愿卡片6 - 左下 -->
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/wishCard6"
|
|
||||||
android:layout_width="60dp"
|
|
||||||
android:layout_height="78dp"
|
|
||||||
android:background="@drawable/bg_wish_card_glass"
|
|
||||||
android:clickable="true"
|
|
||||||
android:focusable="true"
|
|
||||||
android:elevation="6dp"
|
|
||||||
android:gravity="center"
|
|
||||||
android:padding="@dimen/spacing_xs"
|
|
||||||
android:text=""
|
|
||||||
android:textColor="@color/white"
|
|
||||||
android:textSize="@dimen/text_sm"
|
|
||||||
android:shadowColor="#80000000"
|
|
||||||
android:shadowDx="1"
|
|
||||||
android:shadowDy="1"
|
|
||||||
android:shadowRadius="2"
|
|
||||||
app:layout_constraintHorizontal_bias="0.18"
|
|
||||||
app:layout_constraintVertical_bias="0.58"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/banner"
|
|
||||||
app:layout_constraintBottom_toTopOf="@id/bottomArea" />
|
|
||||||
|
|
||||||
<!-- 心愿卡片7 - 右下 -->
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/wishCard7"
|
|
||||||
android:layout_width="54dp"
|
|
||||||
android:layout_height="70dp"
|
|
||||||
android:background="@drawable/bg_wish_card_glass"
|
|
||||||
android:clickable="true"
|
|
||||||
android:focusable="true"
|
|
||||||
android:elevation="6dp"
|
|
||||||
android:gravity="center"
|
|
||||||
android:padding="@dimen/spacing_xs"
|
|
||||||
android:text=""
|
|
||||||
android:textColor="@color/white"
|
|
||||||
android:textSize="@dimen/text_xs"
|
|
||||||
android:shadowColor="#80000000"
|
|
||||||
android:shadowDx="1"
|
|
||||||
android:shadowDy="1"
|
|
||||||
android:shadowRadius="2"
|
|
||||||
app:layout_constraintHorizontal_bias="0.82"
|
|
||||||
app:layout_constraintVertical_bias="0.62"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/banner"
|
|
||||||
app:layout_constraintBottom_toTopOf="@id/bottomArea" />
|
|
||||||
|
|
||||||
<!-- 树干上的金色竖向文字 -->
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/tvTrunkText"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginBottom="100dp"
|
|
||||||
android:background="@drawable/bg_glass_card"
|
|
||||||
android:gravity="center"
|
|
||||||
android:lineSpacingExtra="8dp"
|
|
||||||
android:paddingHorizontal="@dimen/spacing_md"
|
|
||||||
android:paddingVertical="@dimen/page_margin"
|
|
||||||
android:text="元\n旦\n许\n愿\n树"
|
|
||||||
android:textColor="@color/shimmer_gold"
|
|
||||||
android:textSize="@dimen/text_xl"
|
|
||||||
android:textStyle="bold"
|
|
||||||
android:shadowColor="#80000000"
|
|
||||||
android:shadowDx="2"
|
|
||||||
android:shadowDy="2"
|
|
||||||
android:shadowRadius="4"
|
|
||||||
app:layout_constraintBottom_toTopOf="@id/bottomArea"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent" />
|
|
||||||
|
|
||||||
<!-- 底部区域 - 玻璃拟态 -->
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
|
||||||
android:id="@+id/bottomArea"
|
android:id="@+id/bottomArea"
|
||||||
android:layout_width="0dp"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="bottom"
|
||||||
android:background="@drawable/bg_bottom_area_glass"
|
android:background="@drawable/bg_bottom_area_glass"
|
||||||
android:paddingHorizontal="@dimen/page_margin"
|
android:orientation="vertical"
|
||||||
android:paddingTop="@dimen/page_margin"
|
android:paddingHorizontal="16dp"
|
||||||
android:paddingBottom="@dimen/spacing_md"
|
android:paddingTop="12dp"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
android:paddingBottom="8dp">
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent">
|
|
||||||
|
|
||||||
<!-- 进度标签 -->
|
<!-- 进度信息 -->
|
||||||
<TextView
|
<LinearLayout
|
||||||
android:id="@+id/tvWishLabel"
|
android:layout_width="match_parent"
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="✨ 祈愿进度"
|
android:orientation="horizontal">
|
||||||
android:textColor="@color/glass_white_60"
|
|
||||||
android:textSize="@dimen/text_sm"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
|
||||||
|
|
||||||
<!-- 进度数值 -->
|
<TextView
|
||||||
<TextView
|
android:id="@+id/tvWishLabel"
|
||||||
android:id="@+id/tvWishCount"
|
android:layout_width="0dp"
|
||||||
android:layout_width="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_weight="1"
|
||||||
android:text="0/100"
|
android:text="✨ 祈愿进度"
|
||||||
android:textColor="@color/shimmer_gold"
|
android:textColor="@color/glass_white_60"
|
||||||
android:textSize="@dimen/text_md"
|
android:textSize="11sp" />
|
||||||
android:textStyle="bold"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
<TextView
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
android:id="@+id/tvWishCount"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="祈愿值:0/100"
|
||||||
|
android:textColor="@color/shimmer_gold"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
<!-- 进度条 -->
|
<!-- 进度条 -->
|
||||||
<ProgressBar
|
<ProgressBar
|
||||||
android:id="@+id/progressWish"
|
android:id="@+id/progressWish"
|
||||||
style="?android:attr/progressBarStyleHorizontal"
|
style="?android:attr/progressBarStyleHorizontal"
|
||||||
android:layout_width="0dp"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="8dp"
|
android:layout_height="6dp"
|
||||||
android:layout_marginTop="@dimen/spacing_sm"
|
android:layout_marginTop="6dp"
|
||||||
android:max="100"
|
android:max="100"
|
||||||
android:progress="35"
|
android:progress="0"
|
||||||
android:progressDrawable="@drawable/progress_wish_gradient"
|
android:progressDrawable="@drawable/progress_wish_gradient" />
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/tvWishLabel" />
|
|
||||||
|
|
||||||
<!-- 祈愿按钮 -->
|
<!-- 祈愿按钮 -->
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/btnMakeWish"
|
android:id="@+id/btnMakeWish"
|
||||||
android:layout_width="0dp"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="@dimen/button_height"
|
android:layout_height="44dp"
|
||||||
android:layout_marginTop="@dimen/spacing_lg"
|
android:layout_marginTop="10dp"
|
||||||
android:background="@drawable/bg_shimmer_gold_button"
|
android:background="@drawable/bg_shimmer_gold_button"
|
||||||
android:stateListAnimator="@null"
|
android:stateListAnimator="@null"
|
||||||
android:text="🌟 前往祈愿"
|
android:text="🌟 许下心愿"
|
||||||
android:textColor="@color/deep_night_bg"
|
android:textColor="@color/deep_night_bg"
|
||||||
android:textSize="@dimen/text_lg"
|
android:textSize="15sp"
|
||||||
android:textStyle="bold"
|
android:textStyle="bold"
|
||||||
app:backgroundTint="@null"
|
app:backgroundTint="@null"
|
||||||
app:cornerRadius="@dimen/radius_large"
|
app:cornerRadius="22dp" />
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/progressWish" />
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</FrameLayout>
|
||||||
|
|
||||||
<include
|
<include
|
||||||
android:id="@+id/bottomNavInclude"
|
android:id="@+id/bottomNavInclude"
|
||||||
|
|
|
||||||
|
|
@ -80,6 +80,36 @@
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
<!-- 纯文字动态内容区域 -->
|
||||||
|
<ScrollView
|
||||||
|
android:id="@+id/textContentContainer"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:fillViewport="true"
|
||||||
|
android:background="#1A1A1A">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="20dp"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:minHeight="300dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/textContentText"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textSize="18sp"
|
||||||
|
android:textColor="#FFFFFF"
|
||||||
|
android:lineSpacingExtra="8dp"
|
||||||
|
android:gravity="start" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</ScrollView>
|
||||||
|
|
||||||
<!-- 右侧操作按钮(用户头像、关注、点赞、收藏、评论) -->
|
<!-- 右侧操作按钮(用户头像、关注、点赞、收藏、评论) -->
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,19 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- 底部导航 - 深紫色半透明 + 金色发光选中 -->
|
<!-- 底部导航 - 白色背景 + 紫色选中 -->
|
||||||
<com.google.android.material.bottomnavigation.BottomNavigationView xmlns:android="http://schemas.android.com/apk/res/android"
|
<com.google.android.material.bottomnavigation.BottomNavigationView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
android:id="@+id/bottomNavigation"
|
android:id="@+id/bottomNavigation"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="60dp"
|
android:layout_height="48dp"
|
||||||
android:minHeight="60dp"
|
android:minHeight="48dp"
|
||||||
android:background="@drawable/bg_bottom_nav_deep"
|
android:background="@android:color/white"
|
||||||
android:paddingTop="4dp"
|
android:paddingTop="2dp"
|
||||||
android:paddingBottom="4dp"
|
android:paddingBottom="2dp"
|
||||||
android:fitsSystemWindows="false"
|
android:fitsSystemWindows="false"
|
||||||
android:elevation="0dp"
|
android:elevation="8dp"
|
||||||
app:itemIconTint="@color/bottom_nav_icon_glow_color"
|
app:itemIconTint="@color/bottom_nav_icon_glow_color"
|
||||||
app:itemTextColor="@color/bottom_nav_icon_glow_color"
|
app:itemTextColor="@color/bottom_nav_icon_glow_color"
|
||||||
app:itemIconSize="24dp"
|
app:itemIconSize="22dp"
|
||||||
app:itemTextAppearanceActive="@style/BottomNavigationView.TextAppearance"
|
app:itemTextAppearanceActive="@style/BottomNavigationView.TextAppearance"
|
||||||
app:itemTextAppearanceInactive="@style/BottomNavigationView.TextAppearance"
|
app:itemTextAppearanceInactive="@style/BottomNavigationView.TextAppearance"
|
||||||
app:labelVisibilityMode="labeled"
|
app:labelVisibilityMode="labeled"
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,7 @@
|
||||||
android:visibility="gone" />
|
android:visibility="gone" />
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
|
||||||
<!-- 昵称 - 纯白色 -->
|
<!-- 昵称 - 黑色 -->
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/title"
|
android:id="@+id/title"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
|
|
@ -53,7 +53,7 @@
|
||||||
android:ellipsize="end"
|
android:ellipsize="end"
|
||||||
android:maxLines="1"
|
android:maxLines="1"
|
||||||
android:text="会话标题"
|
android:text="会话标题"
|
||||||
android:textColor="@color/white"
|
android:textColor="@color/black"
|
||||||
android:textSize="@dimen/text_lg"
|
android:textSize="@dimen/text_lg"
|
||||||
android:textStyle="bold"
|
android:textStyle="bold"
|
||||||
app:layout_constraintEnd_toStartOf="@id/timeText"
|
app:layout_constraintEnd_toStartOf="@id/timeText"
|
||||||
|
|
@ -61,7 +61,7 @@
|
||||||
app:layout_constraintTop_toTopOf="@id/avatarContainer"
|
app:layout_constraintTop_toTopOf="@id/avatarContainer"
|
||||||
app:layout_constraintBottom_toTopOf="@id/lastMessage" />
|
app:layout_constraintBottom_toTopOf="@id/lastMessage" />
|
||||||
|
|
||||||
<!-- 最后一条消息 - 次要灰色 -->
|
<!-- 最后一条消息 - 灰色 -->
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/lastMessage"
|
android:id="@+id/lastMessage"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
|
|
@ -70,20 +70,20 @@
|
||||||
android:ellipsize="end"
|
android:ellipsize="end"
|
||||||
android:maxLines="1"
|
android:maxLines="1"
|
||||||
android:text="最后一条消息内容预览"
|
android:text="最后一条消息内容预览"
|
||||||
android:textColor="@color/glass_white_60"
|
android:textColor="#666666"
|
||||||
android:textSize="@dimen/text_sm"
|
android:textSize="@dimen/text_sm"
|
||||||
app:layout_constraintBottom_toBottomOf="@id/avatarContainer"
|
app:layout_constraintBottom_toBottomOf="@id/avatarContainer"
|
||||||
app:layout_constraintEnd_toStartOf="@id/unreadBadge"
|
app:layout_constraintEnd_toStartOf="@id/unreadBadge"
|
||||||
app:layout_constraintStart_toStartOf="@id/title"
|
app:layout_constraintStart_toStartOf="@id/title"
|
||||||
app:layout_constraintTop_toBottomOf="@id/title" />
|
app:layout_constraintTop_toBottomOf="@id/title" />
|
||||||
|
|
||||||
<!-- 时间戳 - 更浅的灰色 -->
|
<!-- 时间戳 - 浅灰色 -->
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/timeText"
|
android:id="@+id/timeText"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="12:30"
|
android:text="12:30"
|
||||||
android:textColor="@color/glass_white_40"
|
android:textColor="#999999"
|
||||||
android:textSize="@dimen/text_xs"
|
android:textSize="@dimen/text_xs"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="@id/title" />
|
app:layout_constraintTop_toTopOf="@id/title" />
|
||||||
|
|
@ -106,12 +106,12 @@
|
||||||
app:layout_constraintBottom_toBottomOf="@id/lastMessage"
|
app:layout_constraintBottom_toBottomOf="@id/lastMessage"
|
||||||
app:layout_constraintEnd_toEndOf="parent" />
|
app:layout_constraintEnd_toEndOf="parent" />
|
||||||
|
|
||||||
<!-- 分割线 - 玻璃质感 -->
|
<!-- 分割线 -->
|
||||||
<View
|
<View
|
||||||
android:id="@+id/divider"
|
android:id="@+id/divider"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="1dp"
|
android:layout_height="1dp"
|
||||||
android:background="@color/glass_white_10"
|
android:background="#EEEEEE"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="@id/title" />
|
app:layout_constraintStart_toStartOf="@id/title" />
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,9 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<!-- 封面图片 -->
|
<!-- 封面图片区域 -->
|
||||||
<FrameLayout
|
<FrameLayout
|
||||||
|
android:id="@+id/coverContainer"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="240dp">
|
android:layout_height="240dp">
|
||||||
|
|
||||||
|
|
@ -49,6 +50,29 @@
|
||||||
|
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
|
||||||
|
<!-- 纯文字动态区域(无封面时显示) -->
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/textContentContainer"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:minHeight="120dp"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="12dp"
|
||||||
|
android:background="#F8F8F8"
|
||||||
|
android:visibility="gone">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/worksContentText"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textSize="15sp"
|
||||||
|
android:textColor="#333333"
|
||||||
|
android:lineSpacingExtra="4dp"
|
||||||
|
android:maxLines="6"
|
||||||
|
android:ellipsize="end" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
<!-- 作品信息 -->
|
<!-- 作品信息 -->
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
|
|
||||||
BIN
android-app/img/麻将红中龙_1767927109.png
Normal file
BIN
android-app/img/麻将红中龙_1767927109.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9.6 KiB |
Loading…
Reference in New Issue
Block a user