2025-12-17 15:38:00 +08:00
|
|
|
|
package com.example.livestreaming;
|
|
|
|
|
|
|
2025-12-23 12:39:14 +08:00
|
|
|
|
import android.Manifest;
|
2025-12-17 15:38:00 +08:00
|
|
|
|
import android.content.Context;
|
|
|
|
|
|
import android.content.Intent;
|
2025-12-18 17:33:36 +08:00
|
|
|
|
import android.content.ClipData;
|
|
|
|
|
|
import android.content.ClipboardManager;
|
2026-01-05 17:11:35 +08:00
|
|
|
|
import android.content.pm.PackageManager;
|
2025-12-22 16:31:46 +08:00
|
|
|
|
import android.graphics.drawable.Drawable;
|
2025-12-17 15:38:00 +08:00
|
|
|
|
import android.os.Bundle;
|
2025-12-19 15:11:49 +08:00
|
|
|
|
import android.net.Uri;
|
2025-12-18 14:20:41 +08:00
|
|
|
|
import android.text.TextUtils;
|
2026-01-02 20:39:14 +08:00
|
|
|
|
import android.util.Log;
|
2025-12-18 17:33:36 +08:00
|
|
|
|
import android.view.View;
|
2025-12-18 14:20:41 +08:00
|
|
|
|
import android.widget.EditText;
|
|
|
|
|
|
import android.widget.Toast;
|
2025-12-17 15:38:00 +08:00
|
|
|
|
|
2025-12-22 16:31:46 +08:00
|
|
|
|
import androidx.activity.result.ActivityResultLauncher;
|
|
|
|
|
|
import androidx.activity.result.contract.ActivityResultContracts;
|
2025-12-17 15:38:00 +08:00
|
|
|
|
import androidx.appcompat.app.AppCompatActivity;
|
2026-01-05 17:11:35 +08:00
|
|
|
|
import androidx.core.content.ContextCompat;
|
2025-12-23 15:37:37 +08:00
|
|
|
|
import androidx.core.content.FileProvider;
|
2025-12-18 14:20:41 +08:00
|
|
|
|
import androidx.appcompat.app.AlertDialog;
|
2025-12-24 17:43:14 +08:00
|
|
|
|
import androidx.recyclerview.widget.GridLayoutManager;
|
2025-12-17 15:38:00 +08:00
|
|
|
|
|
2025-12-18 14:20:41 +08:00
|
|
|
|
import com.bumptech.glide.Glide;
|
2025-12-23 12:39:14 +08:00
|
|
|
|
import com.example.livestreaming.BuildConfig;
|
2025-12-17 15:38:00 +08:00
|
|
|
|
import com.example.livestreaming.databinding.ActivityProfileBinding;
|
2025-12-23 12:39:14 +08:00
|
|
|
|
import com.example.livestreaming.ShareUtils;
|
2026-01-05 17:11:35 +08:00
|
|
|
|
import com.example.livestreaming.location.TianDiTuLocationService;
|
2026-01-02 20:39:14 +08:00
|
|
|
|
import com.example.livestreaming.net.ApiClient;
|
|
|
|
|
|
import com.example.livestreaming.net.ApiResponse;
|
2026-01-07 17:36:08 +08:00
|
|
|
|
import com.example.livestreaming.net.PageResponse;
|
2026-01-02 20:39:14 +08:00
|
|
|
|
import com.example.livestreaming.net.UserInfoResponse;
|
2026-01-07 17:36:08 +08:00
|
|
|
|
import com.example.livestreaming.net.WorksResponse;
|
2025-12-17 15:38:00 +08:00
|
|
|
|
import com.google.android.material.bottomnavigation.BottomNavigationView;
|
2025-12-23 12:39:14 +08:00
|
|
|
|
import com.google.android.material.bottomsheet.BottomSheetDialog;
|
2025-12-17 15:38:00 +08:00
|
|
|
|
|
2025-12-24 17:43:14 +08:00
|
|
|
|
import java.util.List;
|
|
|
|
|
|
|
2025-12-23 12:39:14 +08:00
|
|
|
|
import java.io.File;
|
2025-12-22 16:31:46 +08:00
|
|
|
|
import java.text.ParseException;
|
|
|
|
|
|
import java.text.SimpleDateFormat;
|
|
|
|
|
|
import java.util.Calendar;
|
|
|
|
|
|
import java.util.Date;
|
|
|
|
|
|
import java.util.Locale;
|
|
|
|
|
|
|
2026-01-02 20:39:14 +08:00
|
|
|
|
import retrofit2.Call;
|
|
|
|
|
|
import retrofit2.Callback;
|
|
|
|
|
|
import retrofit2.Response;
|
2025-12-22 16:31:46 +08:00
|
|
|
|
|
2025-12-17 15:38:00 +08:00
|
|
|
|
public class ProfileActivity extends AppCompatActivity {
|
|
|
|
|
|
|
2026-01-02 20:39:14 +08:00
|
|
|
|
private static final String TAG = "ProfileActivity";
|
2025-12-17 15:38:00 +08:00
|
|
|
|
private ActivityProfileBinding binding;
|
2026-01-05 17:11:35 +08:00
|
|
|
|
private TianDiTuLocationService locationService;
|
|
|
|
|
|
private ActivityResultLauncher<String[]> requestLocationPermissionLauncher;
|
2025-12-17 15:38:00 +08:00
|
|
|
|
|
2025-12-18 14:20:41 +08:00
|
|
|
|
private static final String PREFS_NAME = "profile_prefs";
|
|
|
|
|
|
private static final String KEY_NAME = "profile_name";
|
|
|
|
|
|
private static final String KEY_BIO = "profile_bio";
|
|
|
|
|
|
private static final String KEY_LEVEL = "profile_level";
|
|
|
|
|
|
private static final String KEY_FANS_BADGE = "profile_fans_badge";
|
|
|
|
|
|
private static final String KEY_BADGE = "profile_badge";
|
|
|
|
|
|
private static final String KEY_AVATAR_RES = "profile_avatar_res";
|
|
|
|
|
|
private static final String KEY_AVATAR_URI = "profile_avatar_uri";
|
|
|
|
|
|
private static final String KEY_BIRTHDAY = "profile_birthday";
|
|
|
|
|
|
private static final String KEY_GENDER = "profile_gender";
|
|
|
|
|
|
private static final String KEY_LOCATION = "profile_location";
|
|
|
|
|
|
|
2025-12-19 10:50:13 +08:00
|
|
|
|
private static final String BIO_HINT_TEXT = "填写个人签名更容易获得关注,点击此处添加";
|
2025-12-22 16:31:46 +08:00
|
|
|
|
|
|
|
|
|
|
private ActivityResultLauncher<Intent> editProfileLauncher;
|
2025-12-24 17:43:14 +08:00
|
|
|
|
private UserWorksAdapter worksAdapter;
|
2026-01-07 17:36:08 +08:00
|
|
|
|
private WorksAdapter myWorksAdapter;
|
2025-12-19 10:50:13 +08:00
|
|
|
|
|
2025-12-17 15:38:00 +08:00
|
|
|
|
public static void start(Context context) {
|
|
|
|
|
|
Intent intent = new Intent(context, ProfileActivity.class);
|
|
|
|
|
|
context.startActivity(intent);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|
protected void onCreate(Bundle savedInstanceState) {
|
|
|
|
|
|
super.onCreate(savedInstanceState);
|
|
|
|
|
|
binding = ActivityProfileBinding.inflate(getLayoutInflater());
|
|
|
|
|
|
setContentView(binding.getRoot());
|
2026-01-05 17:11:35 +08:00
|
|
|
|
|
|
|
|
|
|
// 初始化定位服务
|
|
|
|
|
|
locationService = new TianDiTuLocationService(this);
|
|
|
|
|
|
|
|
|
|
|
|
// 注册位置权限请求
|
|
|
|
|
|
requestLocationPermissionLauncher = registerForActivityResult(
|
|
|
|
|
|
new ActivityResultContracts.RequestMultiplePermissions(),
|
|
|
|
|
|
result -> {
|
|
|
|
|
|
Boolean fineLocation = result.get(Manifest.permission.ACCESS_FINE_LOCATION);
|
|
|
|
|
|
Boolean coarseLocation = result.get(Manifest.permission.ACCESS_COARSE_LOCATION);
|
|
|
|
|
|
|
|
|
|
|
|
if ((fineLocation != null && fineLocation) || (coarseLocation != null && coarseLocation)) {
|
|
|
|
|
|
// 权限已授予,开始定位
|
|
|
|
|
|
startLocationUpdate();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
);
|
2025-12-17 15:38:00 +08:00
|
|
|
|
|
2025-12-22 16:31:46 +08:00
|
|
|
|
// 注册编辑资料页面的结果监听
|
|
|
|
|
|
editProfileLauncher = registerForActivityResult(
|
|
|
|
|
|
new ActivityResultContracts.StartActivityForResult(),
|
|
|
|
|
|
result -> {
|
|
|
|
|
|
// 当从EditProfileActivity返回时,立即刷新所有数据
|
|
|
|
|
|
loadProfileFromPrefs();
|
|
|
|
|
|
loadAndDisplayTags();
|
|
|
|
|
|
loadProfileInfo();
|
|
|
|
|
|
}
|
|
|
|
|
|
);
|
|
|
|
|
|
|
2025-12-18 14:20:41 +08:00
|
|
|
|
loadProfileFromPrefs();
|
2026-01-02 20:39:14 +08:00
|
|
|
|
loadUserInfoFromServer(); // 从服务器加载用户信息
|
2025-12-22 16:31:46 +08:00
|
|
|
|
loadAndDisplayTags();
|
|
|
|
|
|
loadProfileInfo();
|
2025-12-29 18:02:28 +08:00
|
|
|
|
loadFollowStats(); // 加载关注统计
|
2025-12-18 14:20:41 +08:00
|
|
|
|
setupEditableAreas();
|
2025-12-22 16:31:46 +08:00
|
|
|
|
setupAvatarClick();
|
2025-12-18 14:20:41 +08:00
|
|
|
|
setupNavigationClicks();
|
2025-12-24 17:43:14 +08:00
|
|
|
|
setupWorksRecycler();
|
2025-12-18 17:33:36 +08:00
|
|
|
|
setupProfileTabs();
|
2026-01-05 17:11:35 +08:00
|
|
|
|
|
|
|
|
|
|
// 自动获取用户位置并更新IP归属地
|
|
|
|
|
|
requestLocationAndUpdate();
|
2025-12-18 14:20:41 +08:00
|
|
|
|
|
2025-12-17 15:38:00 +08:00
|
|
|
|
BottomNavigationView bottomNavigation = binding.bottomNavInclude.bottomNavigation;
|
|
|
|
|
|
bottomNavigation.setSelectedItemId(R.id.nav_profile);
|
2025-12-22 16:31:46 +08:00
|
|
|
|
|
|
|
|
|
|
// 更新未读消息徽章
|
|
|
|
|
|
UnreadMessageManager.updateBadge(bottomNavigation);
|
|
|
|
|
|
|
2025-12-17 15:38:00 +08:00
|
|
|
|
bottomNavigation.setOnItemSelectedListener(item -> {
|
|
|
|
|
|
int id = item.getItemId();
|
|
|
|
|
|
if (id == R.id.nav_home) {
|
|
|
|
|
|
startActivity(new Intent(this, MainActivity.class));
|
|
|
|
|
|
finish();
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (id == R.id.nav_friends) {
|
2026-01-06 14:24:42 +08:00
|
|
|
|
startActivity(new Intent(this, FishPondWebViewActivity.class));
|
2025-12-17 15:38:00 +08:00
|
|
|
|
finish();
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (id == R.id.nav_wish_tree) {
|
2026-01-06 14:24:42 +08:00
|
|
|
|
WishTreeWebViewActivity.start(this);
|
2025-12-17 15:38:00 +08:00
|
|
|
|
finish();
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (id == R.id.nav_messages) {
|
|
|
|
|
|
MessagesActivity.start(this);
|
|
|
|
|
|
finish();
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
2025-12-31 19:41:22 +08:00
|
|
|
|
if (id == R.id.nav_profile) {
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
2025-12-17 15:38:00 +08:00
|
|
|
|
return true;
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-18 14:20:41 +08:00
|
|
|
|
private void loadProfileFromPrefs() {
|
2025-12-23 15:37:37 +08:00
|
|
|
|
// TODO: 接入后端接口 - 获取用户资料
|
|
|
|
|
|
// 接口路径: GET /api/users/{userId}/profile
|
|
|
|
|
|
// 请求参数:
|
|
|
|
|
|
// - userId: 用户ID(路径参数,当前用户从token中获取)
|
|
|
|
|
|
// 返回数据格式: ApiResponse<UserProfile>
|
|
|
|
|
|
// UserProfile对象应包含: id, name, avatarUrl, bio, level, badge, birthday, gender, location,
|
|
|
|
|
|
// followingCount, fansCount, likesCount等字段
|
|
|
|
|
|
// 首次加载时从接口获取,后续可从本地缓存读取
|
2025-12-18 14:20:41 +08:00
|
|
|
|
String n = getSharedPreferences(PREFS_NAME, MODE_PRIVATE).getString(KEY_NAME, null);
|
|
|
|
|
|
if (!TextUtils.isEmpty(n)) binding.name.setText(n);
|
|
|
|
|
|
|
|
|
|
|
|
String bio = getSharedPreferences(PREFS_NAME, MODE_PRIVATE).getString(KEY_BIO, null);
|
2025-12-19 10:50:13 +08:00
|
|
|
|
if (!TextUtils.isEmpty(bio) && !BIO_HINT_TEXT.equals(bio)) {
|
2025-12-18 14:20:41 +08:00
|
|
|
|
binding.bioText.setText(bio);
|
|
|
|
|
|
binding.bioText.setTextColor(0xFF111111);
|
2025-12-19 10:50:13 +08:00
|
|
|
|
} else {
|
|
|
|
|
|
binding.bioText.setText(BIO_HINT_TEXT);
|
|
|
|
|
|
binding.bioText.setTextColor(0xFF999999);
|
2025-12-18 14:20:41 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
String avatarUri = getSharedPreferences(PREFS_NAME, MODE_PRIVATE).getString(KEY_AVATAR_URI, null);
|
|
|
|
|
|
if (!TextUtils.isEmpty(avatarUri)) {
|
2025-12-23 15:37:37 +08:00
|
|
|
|
Uri uri = Uri.parse(avatarUri);
|
|
|
|
|
|
// 如果是 file:// 协议,尝试转换为 FileProvider URI
|
|
|
|
|
|
if ("file".equals(uri.getScheme())) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
java.io.File file = new java.io.File(uri.getPath());
|
|
|
|
|
|
if (file.exists()) {
|
|
|
|
|
|
uri = FileProvider.getUriForFile(
|
|
|
|
|
|
this,
|
|
|
|
|
|
getPackageName() + ".fileprovider",
|
|
|
|
|
|
file
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
|
// 如果转换失败,使用原始 URI
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-12-19 15:11:49 +08:00
|
|
|
|
Glide.with(this)
|
2025-12-23 15:37:37 +08:00
|
|
|
|
.load(uri)
|
2025-12-19 15:11:49 +08:00
|
|
|
|
.circleCrop()
|
|
|
|
|
|
.error(R.drawable.ic_account_circle_24)
|
2025-12-23 15:37:37 +08:00
|
|
|
|
.placeholder(R.drawable.ic_account_circle_24)
|
2025-12-19 15:11:49 +08:00
|
|
|
|
.into(binding.avatar);
|
2025-12-18 14:20:41 +08:00
|
|
|
|
} else {
|
|
|
|
|
|
int avatarRes = getSharedPreferences(PREFS_NAME, MODE_PRIVATE).getInt(KEY_AVATAR_RES, 0);
|
|
|
|
|
|
if (avatarRes != 0) {
|
2025-12-19 15:11:49 +08:00
|
|
|
|
Glide.with(this)
|
|
|
|
|
|
.load(avatarRes)
|
|
|
|
|
|
.circleCrop()
|
|
|
|
|
|
.error(R.drawable.ic_account_circle_24)
|
|
|
|
|
|
.into(binding.avatar);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
binding.avatar.setImageResource(R.drawable.ic_account_circle_24);
|
2025-12-18 14:20:41 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 等级/称号/徽章:保持固定显示(例如“月亮/星耀/至尊”),不从本地缓存覆盖。
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-02 20:39:14 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 从服务器加载用户信息并同步到本地
|
|
|
|
|
|
*/
|
|
|
|
|
|
private void loadUserInfoFromServer() {
|
|
|
|
|
|
if (!AuthHelper.isLoggedIn(this)) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ApiClient.getService(this).getUserInfo().enqueue(new Callback<ApiResponse<UserInfoResponse>>() {
|
|
|
|
|
|
@Override
|
|
|
|
|
|
public void onResponse(Call<ApiResponse<UserInfoResponse>> call, Response<ApiResponse<UserInfoResponse>> response) {
|
|
|
|
|
|
if (response.isSuccessful() && response.body() != null && response.body().isOk()) {
|
|
|
|
|
|
UserInfoResponse userInfo = response.body().getData();
|
|
|
|
|
|
if (userInfo != null) {
|
|
|
|
|
|
syncUserInfoToLocal(userInfo);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|
public void onFailure(Call<ApiResponse<UserInfoResponse>> call, Throwable t) {
|
|
|
|
|
|
Log.e(TAG, "加载用户信息失败: " + t.getMessage());
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 同步服务器用户信息到本地并更新UI
|
|
|
|
|
|
*/
|
|
|
|
|
|
private void syncUserInfoToLocal(UserInfoResponse userInfo) {
|
|
|
|
|
|
android.content.SharedPreferences.Editor editor = getSharedPreferences(PREFS_NAME, MODE_PRIVATE).edit();
|
|
|
|
|
|
|
|
|
|
|
|
// 同步昵称
|
|
|
|
|
|
if (!TextUtils.isEmpty(userInfo.getNickname())) {
|
|
|
|
|
|
editor.putString(KEY_NAME, userInfo.getNickname());
|
|
|
|
|
|
binding.name.setText(userInfo.getNickname());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 同步个性签名
|
|
|
|
|
|
if (!TextUtils.isEmpty(userInfo.getMark())) {
|
|
|
|
|
|
editor.putString(KEY_BIO, userInfo.getMark());
|
|
|
|
|
|
binding.bioText.setText(userInfo.getMark());
|
|
|
|
|
|
binding.bioText.setTextColor(0xFF111111);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 同步头像
|
|
|
|
|
|
if (!TextUtils.isEmpty(userInfo.getAvatar())) {
|
|
|
|
|
|
String avatarUrl = userInfo.getAvatar();
|
|
|
|
|
|
String baseUrl = ApiClient.getCurrentBaseUrl(ProfileActivity.this);
|
|
|
|
|
|
|
|
|
|
|
|
// 处理相对路径
|
|
|
|
|
|
if (!avatarUrl.startsWith("http://") && !avatarUrl.startsWith("https://")) {
|
|
|
|
|
|
if (avatarUrl.startsWith("crmebimage/")) {
|
|
|
|
|
|
avatarUrl = baseUrl.replace("/api/", "/") + avatarUrl;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
editor.putString(KEY_AVATAR_URI, avatarUrl);
|
|
|
|
|
|
Glide.with(ProfileActivity.this)
|
|
|
|
|
|
.load(avatarUrl)
|
|
|
|
|
|
.circleCrop()
|
|
|
|
|
|
.error(R.drawable.ic_account_circle_24)
|
|
|
|
|
|
.placeholder(R.drawable.ic_account_circle_24)
|
|
|
|
|
|
.into(binding.avatar);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 同步生日
|
|
|
|
|
|
if (!TextUtils.isEmpty(userInfo.getBirthday())) {
|
|
|
|
|
|
editor.putString(KEY_BIRTHDAY, userInfo.getBirthday());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 同步性别
|
|
|
|
|
|
if (userInfo.getSex() != null) {
|
|
|
|
|
|
String gender = "";
|
|
|
|
|
|
switch (userInfo.getSex()) {
|
|
|
|
|
|
case 1: gender = "男"; break;
|
|
|
|
|
|
case 2: gender = "女"; break;
|
|
|
|
|
|
case 3: gender = "保密"; break;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (!TextUtils.isEmpty(gender)) {
|
|
|
|
|
|
editor.putString(KEY_GENDER, gender);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 同步地址
|
|
|
|
|
|
if (!TextUtils.isEmpty(userInfo.getAddres())) {
|
|
|
|
|
|
editor.putString(KEY_LOCATION, userInfo.getAddres());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
editor.apply();
|
|
|
|
|
|
|
|
|
|
|
|
// 刷新标签显示
|
|
|
|
|
|
loadAndDisplayTags();
|
|
|
|
|
|
loadProfileInfo();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-18 14:20:41 +08:00
|
|
|
|
private void setupEditableAreas() {
|
2025-12-23 15:37:37 +08:00
|
|
|
|
// TODO: 接入后端接口 - 更新用户资料
|
|
|
|
|
|
// 接口路径: PUT /api/users/{userId}/profile
|
|
|
|
|
|
// 请求参数:
|
|
|
|
|
|
// - userId: 用户ID(路径参数,从token中获取)
|
|
|
|
|
|
// - name (可选): 昵称
|
|
|
|
|
|
// - bio (可选): 个人签名
|
|
|
|
|
|
// - avatarUrl (可选): 头像URL
|
|
|
|
|
|
// - birthday (可选): 生日
|
|
|
|
|
|
// - gender (可选): 性别
|
|
|
|
|
|
// - location (可选): 所在地
|
|
|
|
|
|
// 返回数据格式: ApiResponse<UserProfile>
|
|
|
|
|
|
// 更新成功后,同步更新本地缓存和界面显示
|
2025-12-18 14:20:41 +08:00
|
|
|
|
binding.name.setOnClickListener(v -> showEditDialog("编辑昵称", binding.name.getText() != null ? binding.name.getText().toString() : "", text -> {
|
|
|
|
|
|
binding.name.setText(text);
|
|
|
|
|
|
getSharedPreferences(PREFS_NAME, MODE_PRIVATE).edit().putString(KEY_NAME, text).apply();
|
|
|
|
|
|
}));
|
|
|
|
|
|
|
2025-12-19 10:50:13 +08:00
|
|
|
|
binding.bioText.setOnClickListener(v -> {
|
|
|
|
|
|
String current = binding.bioText.getText() != null ? binding.bioText.getText().toString() : "";
|
|
|
|
|
|
String initial = BIO_HINT_TEXT.equals(current) ? "" : current;
|
|
|
|
|
|
showEditDialog("编辑签名", initial, text -> {
|
|
|
|
|
|
if (TextUtils.isEmpty(text) || BIO_HINT_TEXT.equals(text)) {
|
|
|
|
|
|
binding.bioText.setText(BIO_HINT_TEXT);
|
|
|
|
|
|
binding.bioText.setTextColor(0xFF999999);
|
|
|
|
|
|
getSharedPreferences(PREFS_NAME, MODE_PRIVATE).edit().remove(KEY_BIO).apply();
|
|
|
|
|
|
} else {
|
|
|
|
|
|
binding.bioText.setText(text);
|
|
|
|
|
|
binding.bioText.setTextColor(0xFF111111);
|
|
|
|
|
|
getSharedPreferences(PREFS_NAME, MODE_PRIVATE).edit().putString(KEY_BIO, text).apply();
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
});
|
2025-12-18 14:20:41 +08:00
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-22 16:31:46 +08:00
|
|
|
|
private void setupAvatarClick() {
|
|
|
|
|
|
binding.avatar.setOnClickListener(v -> {
|
2025-12-22 16:31:46 +08:00
|
|
|
|
AvatarViewerDialog dialog = AvatarViewerDialog.create(this);
|
|
|
|
|
|
|
|
|
|
|
|
// 优先从SharedPreferences读取最新的头像信息(因为ImageView可能还在加载中)
|
|
|
|
|
|
String avatarUri = getSharedPreferences(PREFS_NAME, MODE_PRIVATE).getString(KEY_AVATAR_URI, null);
|
|
|
|
|
|
int avatarRes = getSharedPreferences(PREFS_NAME, MODE_PRIVATE).getInt(KEY_AVATAR_RES, 0);
|
|
|
|
|
|
|
|
|
|
|
|
if (!TextUtils.isEmpty(avatarUri)) {
|
|
|
|
|
|
// 使用URI加载,确保能正确显示
|
|
|
|
|
|
dialog.setAvatarUri(Uri.parse(avatarUri));
|
|
|
|
|
|
} else if (avatarRes != 0) {
|
|
|
|
|
|
dialog.setAvatarResId(avatarRes);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 如果都没有,尝试从ImageView获取Drawable
|
|
|
|
|
|
Drawable drawable = binding.avatar.getDrawable();
|
|
|
|
|
|
if (drawable != null) {
|
|
|
|
|
|
dialog.setAvatarDrawable(drawable);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
dialog.setAvatarResId(R.drawable.ic_account_circle_24);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
dialog.show();
|
2025-12-23 12:39:14 +08:00
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-18 14:20:41 +08:00
|
|
|
|
private void setupNavigationClicks() {
|
2025-12-18 17:33:36 +08:00
|
|
|
|
binding.topActionSearch.setOnClickListener(v -> TabPlaceholderActivity.start(this, "定位/发现"));
|
2025-12-23 18:09:56 +08:00
|
|
|
|
binding.topActionClock.setOnClickListener(v -> {
|
|
|
|
|
|
// 检查登录状态,观看历史需要登录
|
|
|
|
|
|
if (!AuthHelper.requireLogin(this, "查看观看历史需要登录")) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2026-01-05 16:47:07 +08:00
|
|
|
|
MyRecordsActivity.start(this);
|
2025-12-23 18:09:56 +08:00
|
|
|
|
});
|
2026-01-05 16:58:39 +08:00
|
|
|
|
binding.topActionMore.setOnClickListener(v -> showMoreOptionsMenu());
|
2025-12-18 14:20:41 +08:00
|
|
|
|
|
2025-12-18 17:33:36 +08:00
|
|
|
|
binding.copyIdBtn.setOnClickListener(v -> {
|
|
|
|
|
|
String idText = binding.idLine.getText() != null ? binding.idLine.getText().toString() : "";
|
|
|
|
|
|
if (TextUtils.isEmpty(idText)) return;
|
|
|
|
|
|
String digits = idText.replaceAll("\\D+", "");
|
|
|
|
|
|
if (TextUtils.isEmpty(digits)) return;
|
|
|
|
|
|
ClipboardManager cm = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
|
|
|
|
|
|
if (cm != null) {
|
|
|
|
|
|
cm.setPrimaryClip(ClipData.newPlainText("id", digits));
|
|
|
|
|
|
Toast.makeText(this, "已复制:" + digits, Toast.LENGTH_SHORT).show();
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
2025-12-23 15:37:37 +08:00
|
|
|
|
// TODO: 接入后端接口 - 获取关注/粉丝/获赞数量
|
|
|
|
|
|
// 接口路径: GET /api/users/{userId}/stats
|
|
|
|
|
|
// 请求参数:
|
|
|
|
|
|
// - userId: 用户ID(路径参数)
|
|
|
|
|
|
// 返回数据格式: ApiResponse<{followingCount: number, fansCount: number, likesCount: number}>
|
|
|
|
|
|
// 在ProfileActivity加载时调用,更新关注、粉丝、获赞数量显示
|
2025-12-23 18:09:56 +08:00
|
|
|
|
binding.following.setOnClickListener(v -> {
|
|
|
|
|
|
// 检查登录状态,查看关注列表需要登录
|
|
|
|
|
|
if (!AuthHelper.requireLogin(this, "查看关注列表需要登录")) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
FollowingListActivity.start(this);
|
|
|
|
|
|
});
|
|
|
|
|
|
binding.followers.setOnClickListener(v -> {
|
|
|
|
|
|
// 检查登录状态,查看粉丝列表需要登录
|
|
|
|
|
|
if (!AuthHelper.requireLogin(this, "查看粉丝列表需要登录")) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
FansListActivity.start(this);
|
|
|
|
|
|
});
|
|
|
|
|
|
binding.likes.setOnClickListener(v -> {
|
|
|
|
|
|
// 检查登录状态,查看获赞列表需要登录
|
|
|
|
|
|
if (!AuthHelper.requireLogin(this, "查看获赞列表需要登录")) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
LikesListActivity.start(this);
|
|
|
|
|
|
});
|
2025-12-18 14:20:41 +08:00
|
|
|
|
|
2026-01-03 17:01:58 +08:00
|
|
|
|
binding.action1.setOnClickListener(v -> {
|
|
|
|
|
|
// 我的关注
|
|
|
|
|
|
if (!AuthHelper.requireLogin(this, "查看关注列表需要登录")) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
startActivity(new Intent(this, FollowingActivity.class));
|
|
|
|
|
|
});
|
2025-12-23 18:09:56 +08:00
|
|
|
|
binding.action2.setOnClickListener(v -> {
|
2026-01-07 17:36:08 +08:00
|
|
|
|
// 我的点赞(作品+直播间)
|
|
|
|
|
|
if (!AuthHelper.requireLogin(this, "查看点赞需要登录")) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
MyLikesActivity.start(this);
|
|
|
|
|
|
});
|
|
|
|
|
|
binding.action3.setOnClickListener(v -> {
|
|
|
|
|
|
// 我的收藏(作品+直播间)
|
2026-01-03 17:01:58 +08:00
|
|
|
|
if (!AuthHelper.requireLogin(this, "查看收藏需要登录")) {
|
2025-12-23 18:09:56 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
2026-01-07 17:36:08 +08:00
|
|
|
|
MyCollectionsActivity.start(this);
|
2025-12-23 18:09:56 +08:00
|
|
|
|
});
|
2026-01-04 10:13:32 +08:00
|
|
|
|
binding.action4.setOnClickListener(v -> {
|
|
|
|
|
|
// 我的记录 - 跳转到统一记录页面
|
|
|
|
|
|
if (!AuthHelper.requireLogin(this, "查看记录需要登录")) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
MyRecordsActivity.start(this);
|
|
|
|
|
|
});
|
2025-12-18 14:20:41 +08:00
|
|
|
|
|
2025-12-22 16:31:46 +08:00
|
|
|
|
binding.editProfile.setOnClickListener(v -> {
|
2025-12-23 18:09:56 +08:00
|
|
|
|
// 检查登录状态,编辑资料需要登录
|
|
|
|
|
|
if (!AuthHelper.requireLogin(this, "编辑资料需要登录")) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2025-12-22 16:31:46 +08:00
|
|
|
|
Intent intent = new Intent(this, EditProfileActivity.class);
|
|
|
|
|
|
editProfileLauncher.launch(intent);
|
|
|
|
|
|
});
|
2025-12-23 18:09:56 +08:00
|
|
|
|
binding.shareHome.setOnClickListener(v -> {
|
|
|
|
|
|
// 检查登录状态,分享个人主页需要登录
|
|
|
|
|
|
if (!AuthHelper.requireLogin(this, "分享个人主页需要登录")) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
showShareProfileDialog();
|
|
|
|
|
|
});
|
2026-01-03 12:24:05 +08:00
|
|
|
|
|
|
|
|
|
|
// 主播中心按钮点击事件
|
|
|
|
|
|
binding.streamerCenterBtn.setOnClickListener(v -> {
|
|
|
|
|
|
StreamerCenterActivity.start(this);
|
|
|
|
|
|
});
|
|
|
|
|
|
|
2025-12-24 18:11:39 +08:00
|
|
|
|
binding.addFriendBtn.setOnClickListener(v -> {
|
2026-01-07 17:36:08 +08:00
|
|
|
|
// 我的挚友(原添加好友功能已在挚友页面内)
|
|
|
|
|
|
if (!AuthHelper.requireLogin(this, "查看挚友需要登录")) {
|
2025-12-24 18:11:39 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
2026-01-07 17:36:08 +08:00
|
|
|
|
startActivity(new Intent(this, MyFriendsActivity.class));
|
2025-12-24 18:11:39 +08:00
|
|
|
|
});
|
2026-01-04 16:34:10 +08:00
|
|
|
|
|
|
|
|
|
|
// 我的钱包按钮点击事件
|
|
|
|
|
|
binding.walletButton.setOnClickListener(v -> {
|
|
|
|
|
|
// 检查登录状态,查看钱包需要登录
|
|
|
|
|
|
if (!AuthHelper.requireLogin(this, "查看钱包需要登录")) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
startActivity(new Intent(this, WalletActivity.class));
|
|
|
|
|
|
});
|
2025-12-18 14:20:41 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-18 17:33:36 +08:00
|
|
|
|
private void setupProfileTabs() {
|
|
|
|
|
|
showTab(0);
|
|
|
|
|
|
|
|
|
|
|
|
binding.profileTabs.addOnTabSelectedListener(new com.google.android.material.tabs.TabLayout.OnTabSelectedListener() {
|
|
|
|
|
|
@Override
|
|
|
|
|
|
public void onTabSelected(com.google.android.material.tabs.TabLayout.Tab tab) {
|
|
|
|
|
|
if (tab == null) return;
|
|
|
|
|
|
showTab(tab.getPosition());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|
public void onTabUnselected(com.google.android.material.tabs.TabLayout.Tab tab) {
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|
public void onTabReselected(com.google.android.material.tabs.TabLayout.Tab tab) {
|
|
|
|
|
|
if (tab == null) return;
|
|
|
|
|
|
showTab(tab.getPosition());
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
2025-12-23 18:09:56 +08:00
|
|
|
|
// TODO: 接入后端接口 - 发布作品
|
|
|
|
|
|
// 接口路径: POST /api/works
|
|
|
|
|
|
// 请求参数:
|
|
|
|
|
|
// - userId: 用户ID(从token中获取)
|
|
|
|
|
|
// - title: 作品标题
|
|
|
|
|
|
// - description: 作品描述(可选)
|
|
|
|
|
|
// - coverUrl: 封面图片URL(必填,需要先上传图片)
|
|
|
|
|
|
// - videoUrl (可选): 视频URL(如果是视频作品)
|
|
|
|
|
|
// - images (可选): 图片URL列表(如果是图片作品)
|
|
|
|
|
|
// 返回数据格式: ApiResponse<WorkItem>
|
|
|
|
|
|
// WorkItem对象应包含: id, title, coverUrl, likeCount, viewCount, publishTime等字段
|
|
|
|
|
|
// 发布成功后,刷新作品列表显示
|
2025-12-24 17:43:14 +08:00
|
|
|
|
// 空状态的发布按钮
|
2025-12-23 18:09:56 +08:00
|
|
|
|
binding.worksPublishBtn.setOnClickListener(v -> {
|
|
|
|
|
|
// 检查登录状态,发布作品需要登录
|
|
|
|
|
|
if (!AuthHelper.requireLogin(this, "发布作品需要登录")) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2025-12-24 17:43:14 +08:00
|
|
|
|
PublishWorkActivity.start(this);
|
|
|
|
|
|
});
|
|
|
|
|
|
|
2026-01-06 18:23:15 +08:00
|
|
|
|
// 悬浮按钮(固定显示)
|
|
|
|
|
|
binding.fabPublishWork.setOnClickListener(v -> {
|
|
|
|
|
|
// 检查登录状态,发布作品需要登录
|
|
|
|
|
|
if (!AuthHelper.requireLogin(this, "发布作品需要登录")) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
PublishWorkActivity.start(this);
|
|
|
|
|
|
});
|
2025-12-18 17:33:36 +08:00
|
|
|
|
binding.likedGoBrowseBtn.setOnClickListener(v -> startActivity(new Intent(this, MainActivity.class)));
|
|
|
|
|
|
binding.favGoBrowseBtn.setOnClickListener(v -> startActivity(new Intent(this, MainActivity.class)));
|
2025-12-22 16:31:46 +08:00
|
|
|
|
binding.profileEditFromTab.setOnClickListener(v -> {
|
2025-12-23 18:09:56 +08:00
|
|
|
|
// 检查登录状态,编辑资料需要登录
|
|
|
|
|
|
if (!AuthHelper.requireLogin(this, "编辑资料需要登录")) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2025-12-22 16:31:46 +08:00
|
|
|
|
Intent intent = new Intent(this, EditProfileActivity.class);
|
|
|
|
|
|
editProfileLauncher.launch(intent);
|
|
|
|
|
|
});
|
2025-12-18 17:33:36 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-24 17:43:14 +08:00
|
|
|
|
private void setupWorksRecycler() {
|
2026-01-07 17:36:08 +08:00
|
|
|
|
// 设置我的作品区域
|
|
|
|
|
|
myWorksAdapter = new WorksAdapter(work -> {
|
|
|
|
|
|
if (work != null && work.getId() != null) {
|
|
|
|
|
|
WorkDetailActivity.start(this, String.valueOf(work.getId()));
|
2025-12-24 17:43:14 +08:00
|
|
|
|
}
|
|
|
|
|
|
});
|
2026-01-07 17:36:08 +08:00
|
|
|
|
binding.myWorksRecycler.setLayoutManager(new GridLayoutManager(this, 2));
|
|
|
|
|
|
binding.myWorksRecycler.setAdapter(myWorksAdapter);
|
|
|
|
|
|
|
|
|
|
|
|
// 发布按钮点击事件
|
|
|
|
|
|
binding.myWorksPublishBtn.setOnClickListener(v -> {
|
|
|
|
|
|
if (!AuthHelper.requireLogin(this, "发布作品需要登录")) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
PublishWorkActivity.start(this);
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
loadMyWorks();
|
2025-12-24 17:43:14 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-07 17:36:08 +08:00
|
|
|
|
private void loadMyWorks() {
|
|
|
|
|
|
if (!AuthHelper.isLoggedIn(this)) {
|
|
|
|
|
|
// 未登录时显示空状态
|
|
|
|
|
|
binding.myWorksRecycler.setVisibility(View.GONE);
|
|
|
|
|
|
binding.myWorksEmptyState.setVisibility(View.VISIBLE);
|
|
|
|
|
|
binding.myWorksCount.setText("0个作品");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2025-12-24 17:43:14 +08:00
|
|
|
|
|
2026-01-07 17:36:08 +08:00
|
|
|
|
// 获取当前用户ID
|
|
|
|
|
|
String userIdStr = com.example.livestreaming.net.AuthStore.getUserId(this);
|
|
|
|
|
|
if (userIdStr == null || userIdStr.isEmpty()) {
|
|
|
|
|
|
Log.e(TAG, "无法获取用户ID");
|
|
|
|
|
|
showMyWorksEmpty();
|
|
|
|
|
|
return;
|
2025-12-24 17:43:14 +08:00
|
|
|
|
}
|
2026-01-07 17:36:08 +08:00
|
|
|
|
|
|
|
|
|
|
int userId;
|
|
|
|
|
|
try {
|
|
|
|
|
|
userId = Integer.parseInt(userIdStr);
|
|
|
|
|
|
} catch (NumberFormatException e) {
|
|
|
|
|
|
Log.e(TAG, "用户ID格式错误: " + userIdStr);
|
|
|
|
|
|
showMyWorksEmpty();
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ApiClient.getService(this).getUserWorks(userId, 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> works = pageData.getList();
|
|
|
|
|
|
binding.myWorksRecycler.setVisibility(View.VISIBLE);
|
|
|
|
|
|
binding.myWorksEmptyState.setVisibility(View.GONE);
|
|
|
|
|
|
binding.myWorksCount.setText(works.size() + "个作品");
|
|
|
|
|
|
myWorksAdapter.submitList(works);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
showMyWorksEmpty();
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
Log.e(TAG, "加载我的作品失败: " + (response.body() != null ? response.body().getMessage() : "未知错误"));
|
|
|
|
|
|
showMyWorksEmpty();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|
public void onFailure(Call<ApiResponse<PageResponse<WorksResponse>>> call, Throwable t) {
|
|
|
|
|
|
Log.e(TAG, "加载我的作品失败: " + t.getMessage());
|
|
|
|
|
|
showMyWorksEmpty();
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void showMyWorksEmpty() {
|
|
|
|
|
|
binding.myWorksRecycler.setVisibility(View.GONE);
|
|
|
|
|
|
binding.myWorksEmptyState.setVisibility(View.VISIBLE);
|
|
|
|
|
|
binding.myWorksCount.setText("0个作品");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void loadWorks() {
|
|
|
|
|
|
// 旧方法保留兼容,实际使用loadMyWorks
|
|
|
|
|
|
loadMyWorks();
|
2025-12-24 17:43:14 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-18 17:33:36 +08:00
|
|
|
|
private void showTab(int index) {
|
2025-12-23 18:09:56 +08:00
|
|
|
|
// TODO: 接入后端接口 - 获取用户作品列表
|
|
|
|
|
|
// 接口路径: GET /api/users/{userId}/works
|
|
|
|
|
|
// 请求参数:
|
|
|
|
|
|
// - userId: 用户ID(从token中获取)
|
|
|
|
|
|
// - page (可选): 页码
|
|
|
|
|
|
// - pageSize (可选): 每页数量
|
|
|
|
|
|
// 返回数据格式: ApiResponse<List<WorkItem>>
|
|
|
|
|
|
// WorkItem对象应包含: id, title, coverUrl, likeCount, viewCount, publishTime等字段
|
|
|
|
|
|
// TODO: 接入后端接口 - 获取用户收藏列表
|
|
|
|
|
|
// 接口路径: GET /api/users/{userId}/favorites
|
|
|
|
|
|
// 请求参数:
|
|
|
|
|
|
// - userId: 用户ID(从token中获取)
|
|
|
|
|
|
// - page (可选): 页码
|
|
|
|
|
|
// - pageSize (可选): 每页数量
|
|
|
|
|
|
// 返回数据格式: ApiResponse<List<WorkItem>>
|
|
|
|
|
|
// TODO: 接入后端接口 - 获取用户赞过的作品列表
|
|
|
|
|
|
// 接口路径: GET /api/users/{userId}/liked
|
|
|
|
|
|
// 请求参数:
|
|
|
|
|
|
// - userId: 用户ID(从token中获取)
|
|
|
|
|
|
// - page (可选): 页码
|
|
|
|
|
|
// - pageSize (可选): 每页数量
|
|
|
|
|
|
// 返回数据格式: ApiResponse<List<WorkItem>>
|
2025-12-22 16:31:46 +08:00
|
|
|
|
// 标签页顺序:0-作品, 1-收藏, 2-赞过
|
2025-12-18 17:33:36 +08:00
|
|
|
|
binding.tabWorks.setVisibility(index == 0 ? View.VISIBLE : View.GONE);
|
2025-12-22 16:31:46 +08:00
|
|
|
|
binding.tabFavorites.setVisibility(index == 1 ? View.VISIBLE : View.GONE);
|
|
|
|
|
|
binding.tabLiked.setVisibility(index == 2 ? View.VISIBLE : View.GONE);
|
2025-12-24 17:43:14 +08:00
|
|
|
|
|
|
|
|
|
|
// 当切换到作品标签页时,重新加载作品列表
|
|
|
|
|
|
if (index == 0) {
|
|
|
|
|
|
loadWorks();
|
|
|
|
|
|
}
|
2025-12-22 16:31:46 +08:00
|
|
|
|
// "资料"标签页已移除
|
2025-12-18 17:33:36 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-18 14:20:41 +08:00
|
|
|
|
private interface OnTextSaved {
|
|
|
|
|
|
void onSaved(String text);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void showEditDialog(String title, String initialValue, OnTextSaved onSaved) {
|
|
|
|
|
|
EditText editText = new EditText(this);
|
|
|
|
|
|
editText.setText(initialValue != null ? initialValue : "");
|
|
|
|
|
|
editText.setSelection(editText.getText() != null ? editText.getText().length() : 0);
|
2025-12-19 10:50:13 +08:00
|
|
|
|
editText.setTextColor(0xFF111111);
|
|
|
|
|
|
editText.setHintTextColor(0xFF999999);
|
|
|
|
|
|
if ("编辑签名".equals(title)) {
|
|
|
|
|
|
editText.setHint(BIO_HINT_TEXT);
|
|
|
|
|
|
}
|
2025-12-18 14:20:41 +08:00
|
|
|
|
int pad = (int) (16 * getResources().getDisplayMetrics().density);
|
|
|
|
|
|
editText.setPadding(pad, pad, pad, pad);
|
|
|
|
|
|
|
|
|
|
|
|
new AlertDialog.Builder(this)
|
|
|
|
|
|
.setTitle(title)
|
|
|
|
|
|
.setView(editText)
|
|
|
|
|
|
.setNegativeButton("取消", null)
|
|
|
|
|
|
.setPositiveButton("保存", (d, w) -> {
|
|
|
|
|
|
String t = editText.getText() != null ? editText.getText().toString().trim() : "";
|
|
|
|
|
|
if (onSaved != null) onSaved.onSaved(t);
|
|
|
|
|
|
})
|
|
|
|
|
|
.show();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-17 15:38:00 +08:00
|
|
|
|
@Override
|
|
|
|
|
|
protected void onResume() {
|
|
|
|
|
|
super.onResume();
|
|
|
|
|
|
if (binding != null) {
|
2025-12-18 14:20:41 +08:00
|
|
|
|
loadProfileFromPrefs();
|
2025-12-22 16:31:46 +08:00
|
|
|
|
loadAndDisplayTags();
|
|
|
|
|
|
loadProfileInfo();
|
2025-12-29 18:02:28 +08:00
|
|
|
|
loadFollowStats(); // 刷新关注统计
|
2026-01-04 16:34:10 +08:00
|
|
|
|
loadWalletBalance(); // 刷新钱包余额
|
2025-12-24 17:43:14 +08:00
|
|
|
|
loadWorks(); // 重新加载作品列表
|
2025-12-22 16:31:46 +08:00
|
|
|
|
BottomNavigationView bottomNav = binding.bottomNavInclude.bottomNavigation;
|
|
|
|
|
|
bottomNav.setSelectedItemId(R.id.nav_profile);
|
|
|
|
|
|
// 更新未读消息徽章
|
|
|
|
|
|
UnreadMessageManager.updateBadge(bottomNav);
|
2026-01-03 12:24:05 +08:00
|
|
|
|
// 检查主播状态并显示/隐藏主播中心按钮
|
|
|
|
|
|
checkAndUpdateStreamerButton();
|
2026-01-05 17:11:35 +08:00
|
|
|
|
|
|
|
|
|
|
// 自动更新位置信息(每次进入页面时)
|
|
|
|
|
|
autoUpdateLocation();
|
2025-12-22 16:31:46 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-03 12:24:05 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 检查主播状态并更新主播中心按钮的显示
|
|
|
|
|
|
*/
|
|
|
|
|
|
private void checkAndUpdateStreamerButton() {
|
|
|
|
|
|
// 如果用户未登录,隐藏主播中心按钮
|
|
|
|
|
|
if (!AuthHelper.isLoggedIn(this)) {
|
|
|
|
|
|
if (binding.streamerCenterBtn != null) {
|
|
|
|
|
|
binding.streamerCenterBtn.setVisibility(View.GONE);
|
|
|
|
|
|
}
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 检查主播资格
|
|
|
|
|
|
ApiClient.getService(getApplicationContext()).checkStreamerStatus()
|
|
|
|
|
|
.enqueue(new Callback<ApiResponse<java.util.Map<String, Object>>>() {
|
|
|
|
|
|
@Override
|
|
|
|
|
|
public void onResponse(Call<ApiResponse<java.util.Map<String, Object>>> call,
|
|
|
|
|
|
Response<ApiResponse<java.util.Map<String, Object>>> response) {
|
|
|
|
|
|
if (!response.isSuccessful() || response.body() == null) {
|
|
|
|
|
|
// 接口调用失败,隐藏按钮
|
|
|
|
|
|
if (binding.streamerCenterBtn != null) {
|
|
|
|
|
|
binding.streamerCenterBtn.setVisibility(View.GONE);
|
|
|
|
|
|
}
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ApiResponse<java.util.Map<String, Object>> body = response.body();
|
|
|
|
|
|
if (body.getCode() != 200 || body.getData() == null) {
|
|
|
|
|
|
// 接口返回错误,隐藏按钮
|
|
|
|
|
|
if (binding.streamerCenterBtn != null) {
|
|
|
|
|
|
binding.streamerCenterBtn.setVisibility(View.GONE);
|
|
|
|
|
|
}
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
java.util.Map<String, Object> data = body.getData();
|
|
|
|
|
|
Boolean isStreamer = data.get("isStreamer") != null && (Boolean) data.get("isStreamer");
|
|
|
|
|
|
Boolean isBanned = data.get("isBanned") != null && (Boolean) data.get("isBanned");
|
|
|
|
|
|
|
|
|
|
|
|
// 只有认证主播且未被封禁才显示主播中心按钮
|
|
|
|
|
|
if (isStreamer && !isBanned && binding.streamerCenterBtn != null) {
|
|
|
|
|
|
binding.streamerCenterBtn.setVisibility(View.VISIBLE);
|
|
|
|
|
|
} else if (binding.streamerCenterBtn != null) {
|
|
|
|
|
|
binding.streamerCenterBtn.setVisibility(View.GONE);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|
public void onFailure(Call<ApiResponse<java.util.Map<String, Object>>> call, Throwable t) {
|
|
|
|
|
|
// 网络错误,隐藏按钮
|
|
|
|
|
|
if (binding.streamerCenterBtn != null) {
|
|
|
|
|
|
binding.streamerCenterBtn.setVisibility(View.GONE);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-22 16:31:46 +08:00
|
|
|
|
private void loadAndDisplayTags() {
|
|
|
|
|
|
String location = getSharedPreferences(PREFS_NAME, MODE_PRIVATE).getString(KEY_LOCATION, "");
|
|
|
|
|
|
String gender = getSharedPreferences(PREFS_NAME, MODE_PRIVATE).getString(KEY_GENDER, "");
|
|
|
|
|
|
String birthday = getSharedPreferences(PREFS_NAME, MODE_PRIVATE).getString(KEY_BIRTHDAY, "");
|
|
|
|
|
|
|
|
|
|
|
|
// 设置所在地标签 - 支持"省份-城市"格式
|
|
|
|
|
|
if (!TextUtils.isEmpty(location)) {
|
|
|
|
|
|
// 将"省份-城市"格式转换为"省份·城市"显示
|
|
|
|
|
|
String displayLocation = location.replace("-", "·");
|
|
|
|
|
|
binding.tagLocation.setText("IP:" + displayLocation);
|
|
|
|
|
|
binding.tagLocation.setVisibility(View.VISIBLE);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
binding.tagLocation.setText("IP:广西");
|
|
|
|
|
|
binding.tagLocation.setVisibility(View.VISIBLE);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 设置性别标签
|
|
|
|
|
|
if (!TextUtils.isEmpty(gender)) {
|
|
|
|
|
|
if (gender.contains("男")) {
|
|
|
|
|
|
binding.tagGender.setText("男");
|
|
|
|
|
|
} else if (gender.contains("女")) {
|
|
|
|
|
|
binding.tagGender.setText("女");
|
|
|
|
|
|
} else {
|
|
|
|
|
|
binding.tagGender.setText("H");
|
|
|
|
|
|
}
|
|
|
|
|
|
binding.tagGender.setVisibility(View.VISIBLE);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
binding.tagGender.setText("H");
|
|
|
|
|
|
binding.tagGender.setVisibility(View.VISIBLE);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 计算并设置年龄标签
|
|
|
|
|
|
if (!TextUtils.isEmpty(birthday)) {
|
|
|
|
|
|
int age = calculateAge(birthday);
|
|
|
|
|
|
if (age > 0) {
|
|
|
|
|
|
binding.tagAge.setText(age + "岁");
|
|
|
|
|
|
binding.tagAge.setVisibility(View.VISIBLE);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
binding.tagAge.setVisibility(View.GONE);
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
binding.tagAge.setVisibility(View.GONE);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 计算并设置星座标签
|
|
|
|
|
|
if (!TextUtils.isEmpty(birthday)) {
|
|
|
|
|
|
String constellation = calculateConstellation(birthday);
|
|
|
|
|
|
if (!TextUtils.isEmpty(constellation)) {
|
|
|
|
|
|
binding.tagConstellation.setText(constellation);
|
|
|
|
|
|
binding.tagConstellation.setVisibility(View.VISIBLE);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
binding.tagConstellation.setVisibility(View.GONE);
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
binding.tagConstellation.setVisibility(View.GONE);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void loadProfileInfo() {
|
|
|
|
|
|
String name = getSharedPreferences(PREFS_NAME, MODE_PRIVATE).getString(KEY_NAME, "爱你");
|
|
|
|
|
|
String location = getSharedPreferences(PREFS_NAME, MODE_PRIVATE).getString(KEY_LOCATION, "广西");
|
|
|
|
|
|
String bio = getSharedPreferences(PREFS_NAME, MODE_PRIVATE).getString(KEY_BIO, null);
|
|
|
|
|
|
|
|
|
|
|
|
if (binding.profileInfoLine1 != null) {
|
|
|
|
|
|
binding.profileInfoLine1.setText("昵称:" + name);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (binding.profileInfoLine2 != null) {
|
|
|
|
|
|
String locationText = !TextUtils.isEmpty(location) ? location : "广西";
|
|
|
|
|
|
binding.profileInfoLine2.setText("地区:" + locationText);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (binding.profileInfoLine3 != null) {
|
|
|
|
|
|
String bioText = (!TextUtils.isEmpty(bio) && !BIO_HINT_TEXT.equals(bio)) ? bio : "填写个人签名更容易获得关注";
|
|
|
|
|
|
binding.profileInfoLine3.setText("签名:" + bioText);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private int calculateAge(String birthdayStr) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault());
|
|
|
|
|
|
Date birthDate = sdf.parse(birthdayStr);
|
|
|
|
|
|
if (birthDate == null) return 0;
|
|
|
|
|
|
|
|
|
|
|
|
Calendar birth = Calendar.getInstance();
|
|
|
|
|
|
birth.setTime(birthDate);
|
|
|
|
|
|
Calendar now = Calendar.getInstance();
|
|
|
|
|
|
|
|
|
|
|
|
int age = now.get(Calendar.YEAR) - birth.get(Calendar.YEAR);
|
|
|
|
|
|
if (now.get(Calendar.DAY_OF_YEAR) < birth.get(Calendar.DAY_OF_YEAR)) {
|
|
|
|
|
|
age--;
|
|
|
|
|
|
}
|
|
|
|
|
|
return age;
|
|
|
|
|
|
} catch (ParseException e) {
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private String calculateConstellation(String birthdayStr) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault());
|
|
|
|
|
|
Date birthDate = sdf.parse(birthdayStr);
|
|
|
|
|
|
if (birthDate == null) return "";
|
|
|
|
|
|
|
|
|
|
|
|
Calendar cal = Calendar.getInstance();
|
|
|
|
|
|
cal.setTime(birthDate);
|
|
|
|
|
|
int month = cal.get(Calendar.MONTH) + 1; // Calendar.MONTH 从0开始
|
|
|
|
|
|
int day = cal.get(Calendar.DAY_OF_MONTH);
|
|
|
|
|
|
|
|
|
|
|
|
// 星座计算
|
|
|
|
|
|
if ((month == 3 && day >= 21) || (month == 4 && day <= 19)) {
|
|
|
|
|
|
return "白羊座";
|
|
|
|
|
|
} else if ((month == 4 && day >= 20) || (month == 5 && day <= 20)) {
|
|
|
|
|
|
return "金牛座";
|
|
|
|
|
|
} else if ((month == 5 && day >= 21) || (month == 6 && day <= 21)) {
|
|
|
|
|
|
return "双子座";
|
|
|
|
|
|
} else if ((month == 6 && day >= 22) || (month == 7 && day <= 22)) {
|
|
|
|
|
|
return "巨蟹座";
|
|
|
|
|
|
} else if ((month == 7 && day >= 23) || (month == 8 && day <= 22)) {
|
|
|
|
|
|
return "狮子座";
|
|
|
|
|
|
} else if ((month == 8 && day >= 23) || (month == 9 && day <= 22)) {
|
|
|
|
|
|
return "处女座";
|
|
|
|
|
|
} else if ((month == 9 && day >= 23) || (month == 10 && day <= 23)) {
|
|
|
|
|
|
return "天秤座";
|
|
|
|
|
|
} else if ((month == 10 && day >= 24) || (month == 11 && day <= 22)) {
|
|
|
|
|
|
return "天蝎座";
|
|
|
|
|
|
} else if ((month == 11 && day >= 23) || (month == 12 && day <= 21)) {
|
|
|
|
|
|
return "射手座";
|
|
|
|
|
|
} else if ((month == 12 && day >= 22) || (month == 1 && day <= 19)) {
|
|
|
|
|
|
return "摩羯座";
|
|
|
|
|
|
} else if ((month == 1 && day >= 20) || (month == 2 && day <= 18)) {
|
|
|
|
|
|
return "水瓶座";
|
|
|
|
|
|
} else if ((month == 2 && day >= 19) || (month == 3 && day <= 20)) {
|
|
|
|
|
|
return "双鱼座";
|
|
|
|
|
|
}
|
|
|
|
|
|
return "";
|
|
|
|
|
|
} catch (ParseException e) {
|
|
|
|
|
|
return "";
|
2025-12-17 15:38:00 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-01-05 16:58:39 +08:00
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 显示更多选项菜单
|
|
|
|
|
|
*/
|
|
|
|
|
|
private void showMoreOptionsMenu() {
|
|
|
|
|
|
String[] options = {"黑名单管理", "设置", "关于"};
|
|
|
|
|
|
|
|
|
|
|
|
new androidx.appcompat.app.AlertDialog.Builder(this)
|
|
|
|
|
|
.setItems(options, (dialog, which) -> {
|
|
|
|
|
|
switch (which) {
|
|
|
|
|
|
case 0:
|
|
|
|
|
|
// 黑名单管理
|
|
|
|
|
|
if (!AuthHelper.requireLogin(this, "查看黑名单需要登录")) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
BlacklistActivity.start(this);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 1:
|
|
|
|
|
|
// 设置
|
|
|
|
|
|
TabPlaceholderActivity.start(this, "设置");
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 2:
|
|
|
|
|
|
// 关于
|
|
|
|
|
|
TabPlaceholderActivity.start(this, "关于");
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
.show();
|
|
|
|
|
|
}
|
2025-12-23 12:39:14 +08:00
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 显示分享个人主页对话框
|
|
|
|
|
|
*/
|
|
|
|
|
|
private void showShareProfileDialog() {
|
|
|
|
|
|
// 获取用户ID
|
|
|
|
|
|
String idText = binding.idLine.getText() != null ? binding.idLine.getText().toString() : "";
|
|
|
|
|
|
String digits = !TextUtils.isEmpty(idText) ? idText.replaceAll("\\D+", "") : "";
|
|
|
|
|
|
if (TextUtils.isEmpty(digits)) {
|
|
|
|
|
|
digits = "24187196"; // 默认ID
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 直接生成分享链接
|
|
|
|
|
|
String shareLink = ShareUtils.generateProfileShareLink(digits);
|
|
|
|
|
|
ShareUtils.shareLink(this, shareLink, "个人主页", "来看看我的主页吧");
|
|
|
|
|
|
}
|
2025-12-29 18:02:28 +08:00
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 加载关注统计数据
|
|
|
|
|
|
*/
|
|
|
|
|
|
private void loadFollowStats() {
|
|
|
|
|
|
com.example.livestreaming.net.ApiService apiService =
|
2025-12-30 09:31:15 +08:00
|
|
|
|
com.example.livestreaming.net.ApiClient.getService(this);
|
2025-12-29 18:02:28 +08:00
|
|
|
|
retrofit2.Call<com.example.livestreaming.net.ApiResponse<java.util.Map<String, Object>>> call =
|
|
|
|
|
|
apiService.getFollowStats(null); // null表示查询当前用户
|
|
|
|
|
|
|
|
|
|
|
|
call.enqueue(new retrofit2.Callback<com.example.livestreaming.net.ApiResponse<java.util.Map<String, Object>>>() {
|
|
|
|
|
|
@Override
|
|
|
|
|
|
public void onResponse(retrofit2.Call<com.example.livestreaming.net.ApiResponse<java.util.Map<String, Object>>> call,
|
|
|
|
|
|
retrofit2.Response<com.example.livestreaming.net.ApiResponse<java.util.Map<String, Object>>> response) {
|
|
|
|
|
|
if (response.isSuccessful() && response.body() != null) {
|
|
|
|
|
|
com.example.livestreaming.net.ApiResponse<java.util.Map<String, Object>> apiResponse = response.body();
|
|
|
|
|
|
if (apiResponse.getCode() == 200 && apiResponse.getData() != null) {
|
|
|
|
|
|
java.util.Map<String, Object> stats = apiResponse.getData();
|
|
|
|
|
|
|
|
|
|
|
|
// 更新关注数
|
|
|
|
|
|
Object followingCount = stats.get("followingCount");
|
|
|
|
|
|
if (followingCount != null) {
|
2026-01-02 20:39:14 +08:00
|
|
|
|
int count = 0;
|
|
|
|
|
|
if (followingCount instanceof Number) {
|
|
|
|
|
|
count = ((Number) followingCount).intValue();
|
|
|
|
|
|
}
|
|
|
|
|
|
binding.following.setText(count + "\n关注");
|
2026-01-03 17:01:58 +08:00
|
|
|
|
// 更新快捷操作区域的关注数
|
|
|
|
|
|
android.widget.TextView followingCountText = findViewById(R.id.followingCount);
|
|
|
|
|
|
if (followingCountText != null) {
|
|
|
|
|
|
followingCountText.setText(count + "人");
|
|
|
|
|
|
}
|
2025-12-29 18:02:28 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 更新粉丝数
|
|
|
|
|
|
Object followersCount = stats.get("followersCount");
|
|
|
|
|
|
if (followersCount != null) {
|
2026-01-02 20:39:14 +08:00
|
|
|
|
int count = 0;
|
|
|
|
|
|
if (followersCount instanceof Number) {
|
|
|
|
|
|
count = ((Number) followersCount).intValue();
|
|
|
|
|
|
}
|
|
|
|
|
|
binding.followers.setText(count + "\n粉丝");
|
2025-12-29 18:02:28 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|
public void onFailure(retrofit2.Call<com.example.livestreaming.net.ApiResponse<java.util.Map<String, Object>>> call, Throwable t) {
|
|
|
|
|
|
// 忽略错误,使用默认显示
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
2026-01-03 17:01:58 +08:00
|
|
|
|
|
|
|
|
|
|
// 加载收藏数(点赞的直播间数量)
|
|
|
|
|
|
loadLikedRoomsCount();
|
2026-01-05 16:47:07 +08:00
|
|
|
|
|
|
|
|
|
|
// 加载好友数量
|
|
|
|
|
|
loadFriendsCount();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 加载好友数量
|
|
|
|
|
|
*/
|
|
|
|
|
|
private void loadFriendsCount() {
|
|
|
|
|
|
if (!AuthHelper.isLoggedIn(this)) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
String token = com.example.livestreaming.net.AuthStore.getToken(this);
|
|
|
|
|
|
if (token == null) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
String url = ApiConfig.getBaseUrl() + "/api/front/friends?page=1&pageSize=1";
|
|
|
|
|
|
|
|
|
|
|
|
okhttp3.OkHttpClient client = new okhttp3.OkHttpClient();
|
|
|
|
|
|
okhttp3.Request request = new okhttp3.Request.Builder()
|
|
|
|
|
|
.url(url)
|
|
|
|
|
|
.addHeader("Authori-zation", token)
|
|
|
|
|
|
.get()
|
|
|
|
|
|
.build();
|
|
|
|
|
|
|
|
|
|
|
|
client.newCall(request).enqueue(new okhttp3.Callback() {
|
|
|
|
|
|
@Override
|
|
|
|
|
|
public void onFailure(okhttp3.Call call, java.io.IOException e) {
|
|
|
|
|
|
// 忽略错误
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|
public void onResponse(okhttp3.Call call, okhttp3.Response response) throws java.io.IOException {
|
|
|
|
|
|
String body = response.body() != null ? response.body().string() : "";
|
|
|
|
|
|
runOnUiThread(() -> {
|
|
|
|
|
|
try {
|
|
|
|
|
|
org.json.JSONObject json = new org.json.JSONObject(body);
|
|
|
|
|
|
if (json.optInt("code", -1) == 200) {
|
|
|
|
|
|
org.json.JSONObject data = json.optJSONObject("data");
|
|
|
|
|
|
if (data != null) {
|
|
|
|
|
|
long total = data.optLong("total", 0);
|
|
|
|
|
|
android.widget.TextView friendsCountText = findViewById(R.id.friendsCount);
|
|
|
|
|
|
if (friendsCountText != null) {
|
|
|
|
|
|
friendsCountText.setText(total + "人");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
|
// 忽略解析错误
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
2026-01-03 17:01:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 加载收藏数(点赞的直播间数量)
|
|
|
|
|
|
*/
|
|
|
|
|
|
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();
|
2026-01-04 19:24:42 +08:00
|
|
|
|
Long total = pageData.getTotal();
|
2026-01-03 17:01:58 +08:00
|
|
|
|
|
|
|
|
|
|
// 更新快捷操作区域的收藏数
|
|
|
|
|
|
android.widget.TextView likedRoomsCountText = findViewById(R.id.likedRoomsCount);
|
|
|
|
|
|
if (likedRoomsCountText != null) {
|
2026-01-04 19:24:42 +08:00
|
|
|
|
likedRoomsCountText.setText((total != null ? total : 0) + "个直播间");
|
2026-01-03 17:01:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|
public void onFailure(retrofit2.Call<com.example.livestreaming.net.ApiResponse<com.example.livestreaming.net.PageResponse<java.util.Map<String, Object>>>> call, Throwable t) {
|
|
|
|
|
|
// 忽略错误,使用默认显示
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
2025-12-29 18:02:28 +08:00
|
|
|
|
}
|
2026-01-04 16:34:10 +08:00
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 加载钱包余额
|
|
|
|
|
|
*/
|
|
|
|
|
|
private void loadWalletBalance() {
|
|
|
|
|
|
if (!AuthHelper.isLoggedIn(this)) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ApiClient.getService(this).getVirtualBalance()
|
|
|
|
|
|
.enqueue(new Callback<ApiResponse<java.util.Map<String, Object>>>() {
|
|
|
|
|
|
@Override
|
|
|
|
|
|
public void onResponse(Call<ApiResponse<java.util.Map<String, Object>>> call,
|
|
|
|
|
|
Response<ApiResponse<java.util.Map<String, Object>>> response) {
|
|
|
|
|
|
if (response.isSuccessful() && response.body() != null && response.body().isOk()) {
|
|
|
|
|
|
java.util.Map<String, Object> data = response.body().getData();
|
|
|
|
|
|
if (data != null && data.containsKey("balance")) {
|
|
|
|
|
|
Object balanceObj = data.get("balance");
|
|
|
|
|
|
String balanceStr = "0";
|
|
|
|
|
|
if (balanceObj instanceof Number) {
|
|
|
|
|
|
double balance = ((Number) balanceObj).doubleValue();
|
|
|
|
|
|
// 如果是整数,不显示小数点
|
|
|
|
|
|
if (balance == Math.floor(balance)) {
|
|
|
|
|
|
balanceStr = String.valueOf((int) balance);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
balanceStr = String.format("%.2f", balance);
|
|
|
|
|
|
}
|
|
|
|
|
|
} else if (balanceObj instanceof String) {
|
|
|
|
|
|
balanceStr = (String) balanceObj;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (binding.walletBalance != null) {
|
|
|
|
|
|
binding.walletBalance.setText(balanceStr);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|
public void onFailure(Call<ApiResponse<java.util.Map<String, Object>>> call, Throwable t) {
|
|
|
|
|
|
// 忽略错误,使用默认显示
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
2026-01-05 17:11:35 +08:00
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 请求位置权限并更新位置
|
|
|
|
|
|
*/
|
|
|
|
|
|
private void requestLocationAndUpdate() {
|
|
|
|
|
|
Log.d(TAG, "========== 开始位置自动更新流程 ==========");
|
|
|
|
|
|
|
|
|
|
|
|
// 检查是否已有位置权限
|
|
|
|
|
|
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
|
|
|
|
|
|
== PackageManager.PERMISSION_GRANTED
|
|
|
|
|
|
|| ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION)
|
|
|
|
|
|
== PackageManager.PERMISSION_GRANTED) {
|
|
|
|
|
|
Log.d(TAG, "✅ 已有位置权限,直接开始定位");
|
|
|
|
|
|
// 已有权限,直接开始定位
|
|
|
|
|
|
startLocationUpdate();
|
|
|
|
|
|
} else {
|
|
|
|
|
|
Log.d(TAG, "⚠️ 没有位置权限,请求权限");
|
|
|
|
|
|
// 静默请求权限(不显示Toast)
|
|
|
|
|
|
requestLocationPermissionLauncher.launch(new String[]{
|
|
|
|
|
|
Manifest.permission.ACCESS_FINE_LOCATION,
|
|
|
|
|
|
Manifest.permission.ACCESS_COARSE_LOCATION
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 开始定位并更新位置信息
|
|
|
|
|
|
*/
|
|
|
|
|
|
private void startLocationUpdate() {
|
|
|
|
|
|
Log.d(TAG, "📍 调用天地图定位服务...");
|
|
|
|
|
|
|
|
|
|
|
|
locationService.startLocation(new TianDiTuLocationService.OnLocationResultListener() {
|
|
|
|
|
|
@Override
|
|
|
|
|
|
public void onSuccess(String province, String city, String address, double latitude, double longitude) {
|
|
|
|
|
|
Log.d(TAG, "✅ 定位成功 - 省份: " + province + ", 城市: " + city + ", 完整地址: " + address);
|
|
|
|
|
|
Log.d(TAG, "📍 经纬度 - 纬度: " + latitude + ", 经度: " + longitude);
|
|
|
|
|
|
|
|
|
|
|
|
runOnUiThread(() -> {
|
|
|
|
|
|
// 格式化地址:省份-城市
|
|
|
|
|
|
String location = "";
|
|
|
|
|
|
if (!TextUtils.isEmpty(province) && !TextUtils.isEmpty(city)) {
|
|
|
|
|
|
// 如果城市名包含省份名,去掉省份
|
|
|
|
|
|
if (city.startsWith(province)) {
|
|
|
|
|
|
location = city;
|
|
|
|
|
|
Log.d(TAG, "城市名包含省份名,只使用城市: " + location);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
location = province + "-" + city;
|
|
|
|
|
|
Log.d(TAG, "格式化为省份-城市: " + location);
|
|
|
|
|
|
}
|
|
|
|
|
|
} else if (!TextUtils.isEmpty(province)) {
|
|
|
|
|
|
location = province;
|
|
|
|
|
|
Log.d(TAG, "只有省份: " + location);
|
|
|
|
|
|
} else if (!TextUtils.isEmpty(city)) {
|
|
|
|
|
|
location = city;
|
|
|
|
|
|
Log.d(TAG, "只有城市: " + location);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!TextUtils.isEmpty(location)) {
|
|
|
|
|
|
Log.d(TAG, "💾 保存位置到本地: " + location);
|
|
|
|
|
|
|
|
|
|
|
|
// 保存到本地
|
|
|
|
|
|
getSharedPreferences(PREFS_NAME, MODE_PRIVATE)
|
|
|
|
|
|
.edit()
|
|
|
|
|
|
.putString(KEY_LOCATION, location)
|
|
|
|
|
|
.apply();
|
|
|
|
|
|
|
|
|
|
|
|
Log.d(TAG, "🔄 刷新页面显示");
|
|
|
|
|
|
// 刷新显示
|
|
|
|
|
|
loadAndDisplayTags();
|
|
|
|
|
|
|
|
|
|
|
|
Log.d(TAG, "🌐 准备更新到服务器数据库(包含经纬度)");
|
|
|
|
|
|
// 更新到服务器数据库(包含经纬度)
|
|
|
|
|
|
updateLocationToServer(location, latitude, longitude);
|
|
|
|
|
|
|
|
|
|
|
|
Log.d(TAG, "✅ IP归属地更新成功: " + location);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
Log.w(TAG, "⚠️ 位置信息为空,跳过更新");
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|
public void onError(String error) {
|
|
|
|
|
|
// 静默失败,不显示错误提示
|
|
|
|
|
|
Log.e(TAG, "❌ 位置获取失败: " + error);
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 更新位置信息到服务器数据库(包含经纬度)
|
|
|
|
|
|
*/
|
|
|
|
|
|
private void updateLocationToServer(String location, double latitude, double longitude) {
|
|
|
|
|
|
if (!AuthHelper.isLoggedIn(this)) {
|
|
|
|
|
|
Log.w(TAG, "用户未登录,跳过位置更新");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Log.d(TAG, "========== 开始更新位置到服务器 ==========");
|
|
|
|
|
|
Log.d(TAG, "准备更新位置到服务器: " + location);
|
|
|
|
|
|
Log.d(TAG, "经纬度: 纬度=" + latitude + ", 经度=" + longitude);
|
|
|
|
|
|
|
|
|
|
|
|
// 创建更新请求
|
|
|
|
|
|
com.example.livestreaming.net.UserEditRequest request = new com.example.livestreaming.net.UserEditRequest();
|
|
|
|
|
|
request.setAddres(location);
|
|
|
|
|
|
request.setLatitude(latitude);
|
|
|
|
|
|
request.setLongitude(longitude);
|
|
|
|
|
|
|
|
|
|
|
|
Log.d(TAG, "请求对象创建完成");
|
|
|
|
|
|
Log.d(TAG, " - addres: " + request.getAddres());
|
|
|
|
|
|
Log.d(TAG, " - latitude: " + request.getLatitude());
|
|
|
|
|
|
Log.d(TAG, " - longitude: " + request.getLongitude());
|
|
|
|
|
|
Log.d(TAG, " - nickname: " + request.getNickname());
|
|
|
|
|
|
Log.d(TAG, "发送位置更新请求到: /api/front/user/edit");
|
|
|
|
|
|
|
|
|
|
|
|
ApiClient.getService(this).updateUserInfo(request)
|
|
|
|
|
|
.enqueue(new Callback<ApiResponse<Object>>() {
|
|
|
|
|
|
@Override
|
|
|
|
|
|
public void onResponse(Call<ApiResponse<Object>> call, Response<ApiResponse<Object>> response) {
|
|
|
|
|
|
Log.d(TAG, "========== 收到服务器响应 ==========");
|
|
|
|
|
|
Log.d(TAG, "HTTP状态码: " + response.code());
|
|
|
|
|
|
|
|
|
|
|
|
if (response.isSuccessful() && response.body() != null) {
|
|
|
|
|
|
ApiResponse<Object> body = response.body();
|
|
|
|
|
|
Log.d(TAG, "响应体不为空");
|
|
|
|
|
|
Log.d(TAG, " - code: " + body.getCode());
|
|
|
|
|
|
Log.d(TAG, " - message: " + body.getMessage());
|
|
|
|
|
|
Log.d(TAG, " - data: " + body.getData());
|
|
|
|
|
|
|
|
|
|
|
|
if (body.isOk()) {
|
|
|
|
|
|
Log.d(TAG, "✅✅✅ 位置信息(含经纬度)已成功同步到服务器数据库 ✅✅✅");
|
|
|
|
|
|
Log.d(TAG, "更新的位置: " + location);
|
|
|
|
|
|
Log.d(TAG, "更新的经纬度: " + latitude + ", " + longitude);
|
|
|
|
|
|
Toast.makeText(ProfileActivity.this, "位置已更新: " + location, Toast.LENGTH_SHORT).show();
|
|
|
|
|
|
} else {
|
|
|
|
|
|
Log.e(TAG, "❌ 服务器返回错误");
|
|
|
|
|
|
Log.e(TAG, "错误码: " + body.getCode());
|
|
|
|
|
|
Log.e(TAG, "错误信息: " + body.getMessage());
|
|
|
|
|
|
Toast.makeText(ProfileActivity.this, "位置更新失败: " + body.getMessage(), Toast.LENGTH_SHORT).show();
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
Log.e(TAG, "❌ 响应不成功或响应体为空");
|
|
|
|
|
|
Log.e(TAG, "HTTP状态码: " + response.code());
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
if (response.errorBody() != null) {
|
|
|
|
|
|
String errorBody = response.errorBody().string();
|
|
|
|
|
|
Log.e(TAG, "错误响应体: " + errorBody);
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
|
Log.e(TAG, "读取错误响应失败", e);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Log.d(TAG, "========== 位置更新流程结束 ==========");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|
public void onFailure(Call<ApiResponse<Object>> call, Throwable t) {
|
|
|
|
|
|
Log.e(TAG, "========== 网络请求失败 ==========");
|
|
|
|
|
|
Log.e(TAG, "错误类型: " + t.getClass().getName());
|
|
|
|
|
|
Log.e(TAG, "错误消息: " + t.getMessage(), t);
|
|
|
|
|
|
Toast.makeText(ProfileActivity.this, "位置更新网络错误", Toast.LENGTH_SHORT).show();
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 自动更新位置信息(每次进入页面时调用)
|
|
|
|
|
|
* 静默更新,不显示任何提示
|
|
|
|
|
|
*/
|
|
|
|
|
|
private void autoUpdateLocation() {
|
|
|
|
|
|
Log.d(TAG, "========== 自动更新位置开始 ==========");
|
|
|
|
|
|
|
|
|
|
|
|
// 检查是否登录
|
|
|
|
|
|
if (!AuthHelper.isLoggedIn(this)) {
|
|
|
|
|
|
Log.d(TAG, "用户未登录,跳过自动位置更新");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 检查位置权限
|
|
|
|
|
|
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
|
|
|
|
|
|
!= PackageManager.PERMISSION_GRANTED
|
|
|
|
|
|
&& ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION)
|
|
|
|
|
|
!= PackageManager.PERMISSION_GRANTED) {
|
|
|
|
|
|
Log.d(TAG, "没有位置权限,跳过自动位置更新");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Log.d(TAG, "开始自动获取位置...");
|
|
|
|
|
|
|
|
|
|
|
|
// 开始定位
|
|
|
|
|
|
locationService.startLocation(new TianDiTuLocationService.OnLocationResultListener() {
|
|
|
|
|
|
@Override
|
|
|
|
|
|
public void onSuccess(String province, String city, String address, double latitude, double longitude) {
|
|
|
|
|
|
Log.d(TAG, "✅ 自动定位成功");
|
|
|
|
|
|
Log.d(TAG, " 省份: " + province);
|
|
|
|
|
|
Log.d(TAG, " 城市: " + city);
|
|
|
|
|
|
Log.d(TAG, " 完整地址: " + address);
|
|
|
|
|
|
Log.d(TAG, " 纬度: " + latitude);
|
|
|
|
|
|
Log.d(TAG, " 经度: " + longitude);
|
|
|
|
|
|
|
|
|
|
|
|
runOnUiThread(() -> {
|
|
|
|
|
|
// 格式化地址:省份-城市
|
|
|
|
|
|
String location = "";
|
|
|
|
|
|
if (!TextUtils.isEmpty(province) && !TextUtils.isEmpty(city)) {
|
|
|
|
|
|
if (city.startsWith(province)) {
|
|
|
|
|
|
location = city;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
location = province + "-" + city;
|
|
|
|
|
|
}
|
|
|
|
|
|
} else if (!TextUtils.isEmpty(province)) {
|
|
|
|
|
|
location = province;
|
|
|
|
|
|
} else if (!TextUtils.isEmpty(city)) {
|
|
|
|
|
|
location = city;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!TextUtils.isEmpty(location)) {
|
|
|
|
|
|
Log.d(TAG, "格式化后的位置: " + location);
|
|
|
|
|
|
|
|
|
|
|
|
// 保存到本地
|
|
|
|
|
|
getSharedPreferences(PREFS_NAME, MODE_PRIVATE)
|
|
|
|
|
|
.edit()
|
|
|
|
|
|
.putString(KEY_LOCATION, location)
|
|
|
|
|
|
.apply();
|
|
|
|
|
|
|
|
|
|
|
|
// 刷新显示
|
|
|
|
|
|
loadAndDisplayTags();
|
|
|
|
|
|
|
|
|
|
|
|
// 静默更新到服务器(不显示Toast)
|
|
|
|
|
|
updateLocationToServerSilently(location, latitude, longitude);
|
|
|
|
|
|
|
|
|
|
|
|
Log.d(TAG, "✅ 自动位置更新完成: " + location);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
Log.w(TAG, "位置信息为空,跳过更新");
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|
public void onError(String error) {
|
|
|
|
|
|
// 静默失败,只记录日志
|
|
|
|
|
|
Log.d(TAG, "自动定位失败(静默): " + error);
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 静默更新位置到服务器(不显示Toast提示)
|
|
|
|
|
|
*/
|
|
|
|
|
|
private void updateLocationToServerSilently(String location, double latitude, double longitude) {
|
|
|
|
|
|
Log.d(TAG, "========== 静默更新位置到服务器 ==========");
|
|
|
|
|
|
Log.d(TAG, "位置: " + location);
|
|
|
|
|
|
Log.d(TAG, "经纬度: " + latitude + ", " + longitude);
|
|
|
|
|
|
|
|
|
|
|
|
// 创建更新请求
|
|
|
|
|
|
com.example.livestreaming.net.UserEditRequest request = new com.example.livestreaming.net.UserEditRequest();
|
|
|
|
|
|
request.setAddres(location);
|
|
|
|
|
|
request.setLatitude(latitude);
|
|
|
|
|
|
request.setLongitude(longitude);
|
|
|
|
|
|
|
|
|
|
|
|
ApiClient.getService(this).updateUserInfo(request)
|
|
|
|
|
|
.enqueue(new Callback<ApiResponse<Object>>() {
|
|
|
|
|
|
@Override
|
|
|
|
|
|
public void onResponse(Call<ApiResponse<Object>> call, Response<ApiResponse<Object>> response) {
|
|
|
|
|
|
if (response.isSuccessful() && response.body() != null && response.body().isOk()) {
|
|
|
|
|
|
Log.d(TAG, "✅ 位置信息已静默更新到服务器");
|
|
|
|
|
|
Log.d(TAG, " 地址: " + location);
|
|
|
|
|
|
Log.d(TAG, " 经纬度: " + latitude + ", " + longitude);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
Log.w(TAG, "位置更新失败: " + (response.body() != null ? response.body().getMessage() : "未知错误"));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|
public void onFailure(Call<ApiResponse<Object>> call, Throwable t) {
|
|
|
|
|
|
Log.w(TAG, "位置更新网络错误: " + t.getMessage());
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|
protected void onDestroy() {
|
|
|
|
|
|
super.onDestroy();
|
|
|
|
|
|
// 停止定位服务
|
|
|
|
|
|
if (locationService != null) {
|
|
|
|
|
|
locationService.stopLocation();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-12-17 15:38:00 +08:00
|
|
|
|
}
|