Compare commits
10 Commits
398aad437b
...
ce685521de
| Author | SHA1 | Date | |
|---|---|---|---|
| ce685521de | |||
| fb91d2a0cb | |||
| c22fccc96e | |||
| ea70700f44 | |||
| 3c3af19b6d | |||
| e72ace70ca | |||
| e6254b5ea4 | |||
| ac60d8181d | |||
| 98be6c946e | |||
| 29c6c2567c |
1
.idea/.name
generated
Normal file
1
.idea/.name
generated
Normal file
@@ -0,0 +1 @@
|
||||
FindMaimaiUltra
|
||||
9
.idea/FindMaimaiDX_Ultra.iml
generated
Normal file
9
.idea/FindMaimaiDX_Ultra.iml
generated
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
2
.idea/compiler.xml
generated
2
.idea/compiler.xml
generated
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CompilerConfiguration">
|
||||
<bytecodeTargetLevel target="17" />
|
||||
<bytecodeTargetLevel target="21" />
|
||||
</component>
|
||||
</project>
|
||||
@@ -1,3 +1,6 @@
|
||||
# 好啦,这个为爱发电的项目也接近尾声了...
|
||||
后续的更新以及官方权限将会由用户 findmaimai@163.com 控制,这个项目的git就存档啦
|
||||
|
||||
# FindMaimaiUltra
|
||||
|
||||
FindMaimaiUltra 是一个 Android 应用程序,用于查询和展示 Maimai(舞萌)游戏的成绩数据。它提供了丰富的功能,包括成绩查询、歌曲成绩展示、地图功能、搜索和排序功能等。
|
||||
|
||||
@@ -11,7 +11,7 @@ android {
|
||||
minSdk 29
|
||||
targetSdk 34
|
||||
versionCode 1
|
||||
versionName "1.6.4"
|
||||
versionName "1.6.5 beta"
|
||||
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ import org.astral.findmaimaiultra.been.Place;
|
||||
import java.util.List;
|
||||
|
||||
public class PlaceAdapter extends RecyclerView.Adapter<PlaceAdapter.PlaceViewHolder> {
|
||||
|
||||
private String theme;
|
||||
private List<Place> placeList;
|
||||
private OnItemClickListener listener;
|
||||
|
||||
@@ -26,9 +26,10 @@ public class PlaceAdapter extends RecyclerView.Adapter<PlaceAdapter.PlaceViewHol
|
||||
void onItemClick(Place place);
|
||||
}
|
||||
|
||||
public PlaceAdapter(List<Place> placeList, OnItemClickListener listener) {
|
||||
public PlaceAdapter(List<Place> placeList,String theme, OnItemClickListener listener) {
|
||||
this.placeList = placeList;
|
||||
this.listener = listener;
|
||||
this.theme = theme;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@@ -69,6 +70,40 @@ public class PlaceAdapter extends RecyclerView.Adapter<PlaceAdapter.PlaceViewHol
|
||||
} else {
|
||||
holder.imageView.setImageDrawable(ContextCompat.getDrawable(holder.itemView.getContext(), R.drawable.rank_a));
|
||||
}
|
||||
|
||||
//通过theme设置textview颜色
|
||||
if (theme.contains("Pink")) {
|
||||
holder.nameTextView.setTextColor(ContextCompat.getColor(holder.itemView.getContext(), R.color.textcolorPrimary));
|
||||
holder.provinceTextView.setTextColor(ContextCompat.getColor(holder.itemView.getContext(), R.color.textcolorPrimary));
|
||||
holder.cityTextView.setTextColor(ContextCompat.getColor(holder.itemView.getContext(), R.color.textcolorPrimary));
|
||||
holder.areaTextView.setTextColor(ContextCompat.getColor(holder.itemView.getContext(), R.color.textcolorPrimary));
|
||||
holder.addressTextView.setTextColor(ContextCompat.getColor(holder.itemView.getContext(), R.color.textcolorPrimary));
|
||||
} else if (theme.contains("Blue")) {
|
||||
holder.nameTextView.setTextColor(ContextCompat.getColor(holder.itemView.getContext(), R.color.textcolorPrimary2));
|
||||
holder.provinceTextView.setTextColor(ContextCompat.getColor(holder.itemView.getContext(), R.color.textcolorPrimary2));
|
||||
holder.cityTextView.setTextColor(ContextCompat.getColor(holder.itemView.getContext(), R.color.textcolorPrimary2));
|
||||
holder.areaTextView.setTextColor(ContextCompat.getColor(holder.itemView.getContext(), R.color.textcolorPrimary2));
|
||||
holder.addressTextView.setTextColor(ContextCompat.getColor(holder.itemView.getContext(), R.color.textcolorPrimary2));
|
||||
} else if (theme.contains("Green")) {
|
||||
holder.nameTextView.setTextColor(ContextCompat.getColor(holder.itemView.getContext(), R.color.lineBaseGreen));
|
||||
holder.provinceTextView.setTextColor(ContextCompat.getColor(holder.itemView.getContext(), R.color.lineBaseGreen));
|
||||
holder.cityTextView.setTextColor(ContextCompat.getColor(holder.itemView.getContext(), R.color.lineBaseGreen));
|
||||
holder.areaTextView.setTextColor(ContextCompat.getColor(holder.itemView.getContext(), R.color.lineBaseGreen));
|
||||
holder.addressTextView.setTextColor(ContextCompat.getColor(holder.itemView.getContext(), R.color.lineBaseGreen));
|
||||
}else if (theme.contains("White")) {
|
||||
holder.nameTextView.setTextColor(ContextCompat.getColor(holder.itemView.getContext(), R.color.white));
|
||||
holder.provinceTextView.setTextColor(ContextCompat.getColor(holder.itemView.getContext(), R.color.white));
|
||||
holder.cityTextView.setTextColor(ContextCompat.getColor(holder.itemView.getContext(), R.color.white));
|
||||
holder.areaTextView.setTextColor(ContextCompat.getColor(holder.itemView.getContext(), R.color.white));
|
||||
holder.addressTextView.setTextColor(ContextCompat.getColor(holder.itemView.getContext(), R.color.white));
|
||||
}else if (theme.contains("Gray")) {
|
||||
holder.nameTextView.setTextColor(ContextCompat.getColor(holder.itemView.getContext(), R.color.black));
|
||||
holder.provinceTextView.setTextColor(ContextCompat.getColor(holder.itemView.getContext(), R.color.black));
|
||||
holder.cityTextView.setTextColor(ContextCompat.getColor(holder.itemView.getContext(), R.color.black));
|
||||
holder.areaTextView.setTextColor(ContextCompat.getColor(holder.itemView.getContext(), R.color.black));
|
||||
holder.addressTextView.setTextColor(ContextCompat.getColor(holder.itemView.getContext(), R.color.black));
|
||||
}
|
||||
|
||||
Log.i("rating", rating + "|" + place.getName());
|
||||
// 控制竖线的位置
|
||||
controlVerticalLines(holder, place);
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
package org.astral.findmaimaiultra.adapter;
|
||||
|
||||
import android.content.SharedPreferences;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import com.bumptech.glide.Glide;
|
||||
@@ -20,6 +22,7 @@ import java.util.List;
|
||||
public class SuggestMusicRatingAdapter extends RecyclerView.Adapter<SuggestMusicRatingAdapter.ViewHolder> {
|
||||
|
||||
private List<MusicRating> musicRatings;
|
||||
private final SharedPreferences projectE;
|
||||
private OnItemClickListener listener;
|
||||
|
||||
public interface OnItemClickListener {
|
||||
@@ -31,10 +34,12 @@ public class SuggestMusicRatingAdapter extends RecyclerView.Adapter<SuggestMusic
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
public SuggestMusicRatingAdapter(List<MusicRating> musicRatings) {
|
||||
public SuggestMusicRatingAdapter(List<MusicRating> musicRatings, SharedPreferences projectE) {
|
||||
this.musicRatings = musicRatings;
|
||||
this.projectE = projectE;
|
||||
}
|
||||
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
@@ -91,6 +96,26 @@ public class SuggestMusicRatingAdapter extends RecyclerView.Adapter<SuggestMusic
|
||||
listener.onItemClick(musicRating);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// Long-press listener to delete project
|
||||
holder.itemView.setOnLongClickListener(v -> {
|
||||
// Remove project from SharedPreferences
|
||||
String projectKey = "project" + musicRating.getMusicId();
|
||||
if (projectE.contains(projectKey)) {
|
||||
SharedPreferences.Editor editor = projectE.edit();
|
||||
editor.remove(projectKey);
|
||||
editor.apply();
|
||||
|
||||
// Remove item from the list and refresh
|
||||
musicRatings.remove(position);
|
||||
notifyItemRemoved(position);
|
||||
notifyItemRangeChanged(position, musicRatings.size());
|
||||
|
||||
Toast.makeText(v.getContext(), "Project removed", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
private int getAchievementImageResId(int achievement) {
|
||||
|
||||
@@ -9,6 +9,30 @@ public class Place implements Parcelable {
|
||||
private String name;
|
||||
private String province;
|
||||
private String city;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuffer sb = new StringBuffer("Place{");
|
||||
sb.append("id=").append(id);
|
||||
sb.append(", name='").append(name).append('\'');
|
||||
sb.append(", province='").append(province).append('\'');
|
||||
sb.append(", city='").append(city).append('\'');
|
||||
sb.append(", area='").append(area).append('\'');
|
||||
sb.append(", address='").append(address).append('\'');
|
||||
sb.append(", isUse=").append(isUse);
|
||||
sb.append(", x=").append(x);
|
||||
sb.append(", y=").append(y);
|
||||
sb.append(", count=").append(count);
|
||||
sb.append(", good=").append(good);
|
||||
sb.append(", bad=").append(bad);
|
||||
sb.append(", num=").append(num);
|
||||
sb.append(", numJ=").append(numJ);
|
||||
sb.append(", meituan_link='").append(meituan_link).append('\'');
|
||||
sb.append(", douyin_link='").append(douyin_link).append('\'');
|
||||
sb.append('}');
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private String area;
|
||||
private String address;
|
||||
private int isUse;
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
package org.astral.findmaimaiultra.been;
|
||||
|
||||
public class ProjectSong {
|
||||
private int id;
|
||||
private double targetLevel;
|
||||
private double targetA;
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public double getTargetLevel() {
|
||||
return targetLevel;
|
||||
}
|
||||
|
||||
public void setTargetLevel(double targetLevel) {
|
||||
this.targetLevel = targetLevel;
|
||||
}
|
||||
|
||||
public double getTargetA() {
|
||||
return targetA;
|
||||
}
|
||||
|
||||
public void setTargetA(double targetA) {
|
||||
this.targetA = targetA;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package org.astral.findmaimaiultra.been.faker;
|
||||
|
||||
public class MaimaiConfig {
|
||||
/**
|
||||
* API接口地址
|
||||
*/
|
||||
private String api ;
|
||||
|
||||
/**
|
||||
* AES加密密钥
|
||||
*/
|
||||
private String AES_KEY;
|
||||
|
||||
/**
|
||||
* AES加密初始向量
|
||||
*/
|
||||
private String AES_IV ;
|
||||
|
||||
/**
|
||||
* 混淆参数
|
||||
*/
|
||||
private String OBFUSCATE_PARAM;
|
||||
|
||||
public String getApi() {
|
||||
return api;
|
||||
}
|
||||
|
||||
public void setApi(String api) {
|
||||
this.api = api;
|
||||
}
|
||||
|
||||
public String getAES_KEY() {
|
||||
return AES_KEY;
|
||||
}
|
||||
|
||||
public void setAES_KEY(String AES_KEY) {
|
||||
this.AES_KEY = AES_KEY;
|
||||
}
|
||||
|
||||
public String getAES_IV() {
|
||||
return AES_IV;
|
||||
}
|
||||
|
||||
public void setAES_IV(String AES_IV) {
|
||||
this.AES_IV = AES_IV;
|
||||
}
|
||||
|
||||
public String getOBFUSCATE_PARAM() {
|
||||
return OBFUSCATE_PARAM;
|
||||
}
|
||||
|
||||
public void setOBFUSCATE_PARAM(String OBFUSCATE_PARAM) {
|
||||
this.OBFUSCATE_PARAM = OBFUSCATE_PARAM;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
package org.astral.findmaimaiultra.been.faker;
|
||||
import android.util.Log;
|
||||
|
||||
import com.google.gson.*;
|
||||
import okhttp3.*;
|
||||
|
||||
import javax.crypto.*;
|
||||
import javax.crypto.spec.*;
|
||||
import java.io.*;
|
||||
import java.nio.charset.*;
|
||||
import java.security.*;
|
||||
import java.time.*;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.*;
|
||||
import java.util.zip.*;
|
||||
|
||||
/**
|
||||
* @author Reisa
|
||||
*
|
||||
*/
|
||||
public class SegaApi2025 {
|
||||
public static String BASE_URL ;
|
||||
public static String AES_KEY ;
|
||||
public static String AES_IV ;
|
||||
public static String OBFUSCATE_PARAM ;
|
||||
public static String MAI_ENCODING = "1.50";
|
||||
|
||||
private final OkHttpClient httpClient;
|
||||
private final Gson gson;
|
||||
|
||||
public SegaApi2025() {
|
||||
this.httpClient = new OkHttpClient.Builder()
|
||||
.connectTimeout(10, java.util.concurrent.TimeUnit.SECONDS)
|
||||
.readTimeout(30, java.util.concurrent.TimeUnit.SECONDS)
|
||||
.build();
|
||||
this.gson = new GsonBuilder().disableHtmlEscaping().create();
|
||||
}
|
||||
|
||||
private static class AesPkcs7 {
|
||||
private static final String TRANSFORMATION = "AES/CBC/PKCS5Padding"; // Java使用PKCS5Padding(实际等同于PKCS7)
|
||||
private final SecretKeySpec keySpec;
|
||||
private final IvParameterSpec ivSpec;
|
||||
|
||||
public AesPkcs7(String key, String iv) {
|
||||
this.keySpec = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "AES");
|
||||
this.ivSpec = new IvParameterSpec(iv.getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
public byte[] encrypt(byte[] data) throws Exception {
|
||||
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
|
||||
cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
|
||||
return cipher.doFinal(data);
|
||||
}
|
||||
|
||||
public byte[] decrypt(byte[] encryptedData) throws Exception {
|
||||
try {
|
||||
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
|
||||
cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
|
||||
return cipher.doFinal(encryptedData);
|
||||
} catch (Exception e) {
|
||||
System.err.println("[解密错误]:" + e.getMessage());
|
||||
return encryptedData; // 与Python版一致:失败时返回原始数据
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 生成API哈希值
|
||||
private String getHashApi(String apiName) throws NoSuchAlgorithmException {
|
||||
String input = apiName + "MaimaiChn" + OBFUSCATE_PARAM;
|
||||
|
||||
MessageDigest md = MessageDigest.getInstance("MD5");
|
||||
byte[] hashBytes = md.digest(input.getBytes(StandardCharsets.UTF_8));
|
||||
|
||||
StringBuilder hexString = new StringBuilder();
|
||||
for (byte b : hashBytes) {
|
||||
String hex = String.format("%02x", b);
|
||||
hexString.append(hex);
|
||||
}
|
||||
return hexString.toString();
|
||||
}
|
||||
|
||||
// 主API调用方法
|
||||
public JsonObject sdgbApi(String data, String apiName, String userId,String KEYCHIP_ID) throws Exception {
|
||||
// Log.d("123456",BASE_URL);
|
||||
// 1. 参数校验
|
||||
Objects.requireNonNull(apiName, "API名称不能为空");
|
||||
|
||||
// 2. 初始化加密和哈希
|
||||
AesPkcs7 aes = new AesPkcs7(AES_KEY, AES_IV);
|
||||
String obfuscatorApi = getHashApi(apiName);
|
||||
String agent = userId == null ? KEYCHIP_ID : userId;
|
||||
|
||||
// 3. 数据处理:JSON → 压缩 → 加密
|
||||
byte[] compressedData = compress(data.getBytes(StandardCharsets.UTF_8));
|
||||
byte[] encryptedData = aes.encrypt(compressedData);
|
||||
|
||||
// 4. 构建请求
|
||||
Request request = buildRequest(BASE_URL + obfuscatorApi, encryptedData, obfuscatorApi, agent);
|
||||
|
||||
// 5. 发送请求并处理响应
|
||||
try (Response response = httpClient.newCall(request).execute()) {
|
||||
if (!response.isSuccessful()) {
|
||||
throw new IOException("HTTP请求失败: " + response.code());
|
||||
}
|
||||
|
||||
byte[] decryptedData = aes.decrypt(response.body().bytes());
|
||||
byte[] decompressedData;
|
||||
|
||||
// 尝试解压(检查zlib头)
|
||||
if (decryptedData.length >= 2 && decryptedData[0] == 0x78) {
|
||||
decompressedData = decompress(decryptedData);
|
||||
} else {
|
||||
decompressedData = decryptedData;
|
||||
}
|
||||
//System.out.println(new String(decompressedData, StandardCharsets.UTF_8));
|
||||
return JsonParser.parseString(new String(decompressedData, StandardCharsets.UTF_8))
|
||||
.getAsJsonObject();
|
||||
}
|
||||
}
|
||||
|
||||
private static String bytesToHex(byte[] bytes) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (byte b : bytes) {
|
||||
sb.append(String.format("%02x", b));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private Request buildRequest(String url, byte[] body, String obfuscatorApi, String agent) {
|
||||
return new Request.Builder()
|
||||
.url(url)
|
||||
.header("Content-Type", "application/json")
|
||||
.header("User-Agent", obfuscatorApi + "#" + agent)
|
||||
.header("charset", "UTF-8")
|
||||
.header("Mai-Encoding", MAI_ENCODING)
|
||||
.header("Content-Encoding", "deflate")
|
||||
.header("Accept-Encoding", new String(Base64.getDecoder().decode("QEBAU0tJUF9IRUFERVJAQEA=")))
|
||||
.header("Expect", "100-continue")
|
||||
.post(RequestBody.create(body, MediaType.get("application/json")))
|
||||
.build();
|
||||
}
|
||||
|
||||
private byte[] compress(byte[] data) throws IOException {
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
try (DeflaterOutputStream dos = new DeflaterOutputStream(bos)) {
|
||||
dos.write(data);
|
||||
}
|
||||
return bos.toByteArray();
|
||||
}
|
||||
|
||||
private byte[] decompress(byte[] data) throws IOException {
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
try (InflaterInputStream iis = new InflaterInputStream(new ByteArrayInputStream(data))) {
|
||||
byte[] buffer = new byte[1024];
|
||||
int len;
|
||||
while ((len = iis.read(buffer)) > 0) {
|
||||
bos.write(buffer, 0, len);
|
||||
}
|
||||
}
|
||||
return bos.toByteArray();
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
SegaApi2025 api = new SegaApi2025();
|
||||
|
||||
// 测试sdgbApi
|
||||
JsonObject testData = new JsonObject();
|
||||
testData.addProperty("userId", Integer.parseInt("11931174"));
|
||||
testData.addProperty("nextIndex",Long.parseLong("10000000000") * 5);
|
||||
testData.addProperty("maxCount",9999);
|
||||
// JsonObject result = api.sdgbApi(testData.toString(), "GetUserItemApi", "11931174");
|
||||
// System.out.println("API响应: " + result.toString());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,455 @@
|
||||
package org.astral.findmaimaiultra.service;
|
||||
|
||||
import static org.astral.findmaimaiultra.been.faker.SegaApi2025.AES_IV;
|
||||
import static org.astral.findmaimaiultra.been.faker.SegaApi2025.AES_KEY;
|
||||
import static org.astral.findmaimaiultra.been.faker.SegaApi2025.BASE_URL;
|
||||
import static org.astral.findmaimaiultra.been.faker.SegaApi2025.OBFUSCATE_PARAM;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.util.Log;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
|
||||
import org.astral.findmaimaiultra.been.faker.MaimaiConfig;
|
||||
import org.astral.findmaimaiultra.been.faker.SegaApi2025;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.RequestBody;
|
||||
import okhttp3.Response;
|
||||
|
||||
public class InMemoryJarLoader {
|
||||
public static SegaApi2025 segaApi2025 = new SegaApi2025();
|
||||
|
||||
private static final String TAG = "JarClient";
|
||||
private static final String SERVER_URL = "http://100.95.217.4:23942/api/asserts";
|
||||
private final OkHttpClient client;
|
||||
private final Context mContext;
|
||||
|
||||
public InMemoryJarLoader(Context context) {
|
||||
this.mContext = context;
|
||||
this.client = new OkHttpClient.Builder()
|
||||
.connectTimeout(30, TimeUnit.SECONDS)
|
||||
.readTimeout(60, TimeUnit.SECONDS)
|
||||
.retryOnConnectionFailure(true)
|
||||
.build();
|
||||
}
|
||||
|
||||
public void loadAndProcess() {
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
Log.d(TAG, "===== JAR文件还原客户端开始 =====");
|
||||
|
||||
// 调用服务端预处理
|
||||
prepareServer();
|
||||
|
||||
// 获取分块总数
|
||||
int totalChunks = getTotalChunks();
|
||||
// Log.d(TAG, "发现" + totalChunks + "个分块,开始下载...");
|
||||
|
||||
if (totalChunks <= 0) {
|
||||
Log.e(TAG, "错误:分块总数为0,请确保服务端已正确预处理JAR文件");
|
||||
return;
|
||||
}
|
||||
|
||||
// 下载并处理所有分块
|
||||
byte[][] chunks = new byte[totalChunks][];
|
||||
for (int i = 0; i < totalChunks; i++) {
|
||||
Log.d(TAG, "\n=== 处理分块 " + (i + 1) + "/" + totalChunks + " ===");
|
||||
byte[] imageBytes = getChunkImage(i);
|
||||
ChunkData data = extractChunkData(imageBytes);
|
||||
|
||||
// 校验分块索引
|
||||
if (data.chunkIndex != i) {
|
||||
throw new RuntimeException("分块顺序错误:预期索引 " + i + ",实际 " + data.chunkIndex);
|
||||
}
|
||||
|
||||
// Log.d(TAG, "成功提取分块数据,大小: " + data.data.length + " 字节");
|
||||
chunks[i] = data.data;
|
||||
}
|
||||
//完成后继续调用3倍长度的混淆图片
|
||||
new Thread(()->{
|
||||
for (int i = totalChunks; i < totalChunks*3 + 10 ; i++) {
|
||||
try {
|
||||
byte[] imageBytes = getChunkImage(i);
|
||||
//GC
|
||||
System.gc();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
|
||||
// 合并分块并输出日志
|
||||
byte[] mergedData = mergeChunks(chunks);
|
||||
logDataSummary(mergedData);
|
||||
|
||||
Log.d(TAG, "\n===== 数据处理完成 =====");
|
||||
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "\n===== 操作失败:" + e.getMessage() + " =====", e);
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
/**
|
||||
* 调用服务端预处理接口,生成JAR分块
|
||||
*/
|
||||
private void prepareServer() throws IOException {
|
||||
// Log.d(TAG, "\n=== 正在请求服务端预处理 ===");
|
||||
// Log.d(TAG, "请求URL: " + SERVER_URL + "/prepare");
|
||||
|
||||
Request request = new Request.Builder()
|
||||
.url(SERVER_URL + "/prepare")
|
||||
.post(RequestBody.create(new byte[0], null))
|
||||
.build();
|
||||
|
||||
try (Response response = client.newCall(request).execute()) {
|
||||
// Log.d(TAG, "响应状态码: " + response.code());
|
||||
|
||||
if (!response.isSuccessful()) {
|
||||
String errorBody = response.body() != null ? response.body().string() : "无响应内容";
|
||||
throw new IOException("服务端预处理失败,状态码: " + response.code() + ",错误信息: " + errorBody);
|
||||
}
|
||||
|
||||
String responseBody = response.body().string();
|
||||
// Log.d(TAG, "服务端响应: " + responseBody);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取分块总数
|
||||
*/
|
||||
private int getTotalChunks() throws IOException {
|
||||
// Log.d(TAG, "\n=== 正在获取分块总数 ===");
|
||||
// Log.d(TAG, "请求URL: " + SERVER_URL + "/total-chunks");
|
||||
|
||||
Request request = new Request.Builder()
|
||||
.url(SERVER_URL + "/total-chunks")
|
||||
.build();
|
||||
|
||||
try (Response response = client.newCall(request).execute()) {
|
||||
// Log.d(TAG, "响应状态码: " + response.code());
|
||||
|
||||
if (!response.isSuccessful()) {
|
||||
String errorBody = response.body() != null ? response.body().string() : "无响应内容";
|
||||
throw new IOException("获取分块总数失败,状态码: " + response.code() + ",错误信息: " + errorBody);
|
||||
}
|
||||
|
||||
String responseBody = response.body().string();
|
||||
// Log.d(TAG, "分块总数: " + responseBody);
|
||||
|
||||
try {
|
||||
return Integer.parseInt(responseBody);
|
||||
} catch (NumberFormatException e) {
|
||||
throw new IOException("无效的分块总数格式: " + responseBody);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定索引的分块图片
|
||||
*/
|
||||
private byte[] getChunkImage(int index) throws IOException {
|
||||
// Log.d(TAG, "\n=== 正在获取分块图片 " + index + " ===");
|
||||
// Log.d(TAG, "请求URL: " + SERVER_URL + "/chunk/" + index);
|
||||
|
||||
Request request = new Request.Builder()
|
||||
.url(SERVER_URL + "/chunk/" + index)
|
||||
.build();
|
||||
|
||||
try (Response response = client.newCall(request).execute()) {
|
||||
// Log.d(TAG, "响应状态码: " + response.code());
|
||||
|
||||
if (!response.isSuccessful()) {
|
||||
String errorBody = response.body() != null ? response.body().string() : "无响应内容";
|
||||
throw new IOException("获取分块图片失败,状态码: " + response.code() + ",错误信息: " + errorBody);
|
||||
}
|
||||
|
||||
byte[] imageBytes = response.body().bytes();
|
||||
// Log.d(TAG, "图片大小: " + imageBytes.length + " 字节");
|
||||
|
||||
// 保存图片到临时文件(用于调试)
|
||||
//saveDebugImage(imageBytes, "chunk_" + index + ".png");
|
||||
|
||||
return imageBytes;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从图片中提取分块数据(完全复刻原Java逻辑)
|
||||
*/
|
||||
private ChunkData extractChunkData(byte[] imageBytes) throws IOException {
|
||||
// Log.d(TAG, "\n=== 正在从图片中提取数据 ===");
|
||||
|
||||
try {
|
||||
// 解析图片(Android平台使用Bitmap替代BufferedImage)
|
||||
Bitmap bitmap = BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.length);
|
||||
int width = bitmap.getWidth();
|
||||
int height = bitmap.getHeight();
|
||||
|
||||
// Log.d(TAG, "图片尺寸: " + width + "x" + height);
|
||||
|
||||
// 1. 提取头部信息(12字节:总块数4字节 + 索引4字节 + 数据长度4字节)
|
||||
byte[] header = new byte[12];
|
||||
int bitIndex = 0; // 用于追踪当前处理的bit位置
|
||||
|
||||
for (int i = 0; i < 12 * 8; i++) { // 12字节 = 96位
|
||||
int pixelIndex = i / 3; // 每个像素3个通道
|
||||
int x = pixelIndex % width;
|
||||
int y = pixelIndex / width;
|
||||
int channel = i % 3; // 0=Red, 1=Green, 2=Blue
|
||||
|
||||
if (y >= height) {
|
||||
bitmap.recycle();
|
||||
throw new RuntimeException("图片损坏,头部信息提取越界");
|
||||
}
|
||||
|
||||
int rgb = bitmap.getPixel(x, y);
|
||||
int bit;
|
||||
switch (channel) {
|
||||
case 0:
|
||||
bit = (rgb >> 16) & 1;
|
||||
break;
|
||||
// Red通道最低位
|
||||
case 1:
|
||||
bit = (rgb >> 8) & 1;
|
||||
break;
|
||||
// Green通道最低位
|
||||
case 2:
|
||||
bit = rgb & 1;
|
||||
break;
|
||||
// Blue通道最低位
|
||||
default:
|
||||
bit = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
// 组装头部字节(高位在前)
|
||||
header[bitIndex / 8] |= (bit << (7 - (bitIndex % 8)));
|
||||
bitIndex++;
|
||||
}
|
||||
|
||||
// 解析头部信息
|
||||
int totalChunks = ((header[0] & 0xFF) << 24) | ((header[1] & 0xFF) << 16)
|
||||
| ((header[2] & 0xFF) << 8) | (header[3] & 0xFF);
|
||||
int chunkIndex = ((header[4] & 0xFF) << 24) | ((header[5] & 0xFF) << 16)
|
||||
| ((header[6] & 0xFF) << 8) | (header[7] & 0xFF);
|
||||
int dataLength = ((header[8] & 0xFF) << 24) | ((header[9] & 0xFF) << 16)
|
||||
| ((header[10] & 0xFF) << 8) | (header[11] & 0xFF);
|
||||
|
||||
// Log.d(TAG, "头部信息解析结果:");
|
||||
// Log.d(TAG, "- 总块数: " + totalChunks);
|
||||
// Log.d(TAG, "- 当前索引: " + chunkIndex);
|
||||
// Log.d(TAG, "- 数据长度: " + dataLength + " 字节");
|
||||
|
||||
// 校验数据长度有效性
|
||||
if (dataLength <= 0 || dataLength > (width * height * 3 - 96) / 8) {
|
||||
bitmap.recycle();
|
||||
throw new RuntimeException("无效的数据长度(可能图片损坏): " + dataLength);
|
||||
}
|
||||
|
||||
// 2. 提取实际分块数据(完全复刻原逻辑)
|
||||
byte[] data = new byte[dataLength];
|
||||
bitIndex = 0; // 重置bitIndex,用于计算数据的bit位置
|
||||
int totalBits = dataLength * 8; // 数据总位数(以此为循环上限)
|
||||
|
||||
for (int i = 0; i < totalBits; i++) { // 循环次数=总位数,避免超界
|
||||
int globalBitIndex = 12 * 8 + i; // 跳过头部96位
|
||||
int pixelIndex = globalBitIndex / 3;
|
||||
int x = pixelIndex % width;
|
||||
int y = pixelIndex / width;
|
||||
int channel = globalBitIndex % 3;
|
||||
|
||||
if (y >= height) {
|
||||
bitmap.recycle();
|
||||
throw new RuntimeException("图片损坏,数据提取越界(像素行超出)");
|
||||
}
|
||||
|
||||
int rgb = bitmap.getPixel(x, y);
|
||||
int bit;
|
||||
switch (channel) {
|
||||
case 0:
|
||||
bit = (rgb >> 16) & 1;
|
||||
break;
|
||||
case 1:
|
||||
bit = (rgb >> 8) & 1;
|
||||
break;
|
||||
case 2:
|
||||
bit = rgb & 1;
|
||||
break;
|
||||
default:
|
||||
bit = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
// 计算当前字节索引(确保不超过data数组长度)
|
||||
int byteIndex = bitIndex / 8;
|
||||
if (byteIndex >= dataLength) {
|
||||
bitmap.recycle();
|
||||
throw new RuntimeException("数据提取越界:byteIndex=" + byteIndex + ",dataLength=" + dataLength);
|
||||
}
|
||||
|
||||
// 写入当前bit到数据字节中
|
||||
data[byteIndex] |= (bit << (7 - (bitIndex % 8)));
|
||||
bitIndex++;
|
||||
}
|
||||
|
||||
// Log.d(TAG, "成功提取数据,校验和: " + calculateChecksum(data));
|
||||
bitmap.recycle(); // 及时回收Bitmap资源
|
||||
return new ChunkData(totalChunks, chunkIndex, data);
|
||||
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "提取数据失败: " + e.getMessage());
|
||||
saveDebugImage(imageBytes, "error_image.png"); // 保存错误图片用于调试
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 合并分块数据
|
||||
*/
|
||||
private byte[] mergeChunks(byte[][] chunks) throws IOException {
|
||||
// Log.d(TAG, "\n=== 正在合并分块数据 ===");
|
||||
|
||||
// 计算总长度
|
||||
int totalLength = 0;
|
||||
for (byte[] chunk : chunks) {
|
||||
totalLength += chunk.length;
|
||||
}
|
||||
|
||||
// Log.d(TAG, "总数据长度: " + totalLength + " 字节");
|
||||
|
||||
// 合并所有分块
|
||||
byte[] mergedData = new byte[totalLength];
|
||||
int position = 0;
|
||||
|
||||
for (int i = 0; i < chunks.length; i++) {
|
||||
byte[] chunk = chunks[i];
|
||||
System.arraycopy(chunk, 0, mergedData, position, chunk.length);
|
||||
position += chunk.length;
|
||||
// Log.d(TAG, "已合并分块 " + (i + 1) + "/" + chunks.length);
|
||||
}
|
||||
|
||||
// Log.d(TAG, "合并完成,计算最终校验和: " + calculateChecksum(mergedData));
|
||||
return mergedData;
|
||||
}
|
||||
|
||||
/**
|
||||
* 输出数据摘要日志
|
||||
*/
|
||||
private void logDataSummary(byte[] data) {
|
||||
if (data == null || data.length == 0) {
|
||||
Log.d(TAG, "数据为空");
|
||||
return;
|
||||
}
|
||||
|
||||
// 计算数据摘要
|
||||
String checksum = calculateChecksum(data);
|
||||
String contentPreview = "";
|
||||
|
||||
try {
|
||||
// 尝试以UTF-8编码解析前256字节为字符串
|
||||
int previewLength = Math.min(256, data.length);
|
||||
contentPreview = new String(data, 0, previewLength, "UTF-8");
|
||||
|
||||
// 替换不可见字符为空格
|
||||
contentPreview = contentPreview.replaceAll("[\\x00-\\x1F\\x7F]", " ");
|
||||
|
||||
if (data.length > previewLength) {
|
||||
contentPreview += " ...";
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// 编码解析失败时使用十六进制预览
|
||||
StringBuilder hexPreview = new StringBuilder();
|
||||
int hexLength = Math.min(64, data.length);
|
||||
for (int i = 0; i < hexLength; i++) {
|
||||
hexPreview.append(String.format("%02X ", data[i]));
|
||||
if ((i + 1) % 16 == 0) hexPreview.append("\n");
|
||||
}
|
||||
contentPreview = "十六进制预览:\n" + hexPreview + (data.length > hexLength ? " ..." : "");
|
||||
}
|
||||
//
|
||||
// // 输出数据摘要
|
||||
// Log.d(TAG, "===== 合并后数据摘要 =====");
|
||||
// Log.d(TAG, "总大小: " + data.length + " 字节");
|
||||
// Log.d(TAG, "校验和: " + checksum);
|
||||
// Log.d(TAG, "内容预览:\n" + contentPreview);
|
||||
// Log.d(TAG, "=========================");
|
||||
|
||||
MaimaiConfig maimaiConfig = new Gson().fromJson(contentPreview, MaimaiConfig.class);
|
||||
// Log.d(TAG, maimaiConfig.getApi());
|
||||
// Log.d(TAG, maimaiConfig.getAES_KEY());
|
||||
// Log.d(TAG, maimaiConfig.getAES_IV());
|
||||
// Log.d(TAG, maimaiConfig.getOBFUSCATE_PARAM());
|
||||
BASE_URL = maimaiConfig.getApi();
|
||||
AES_KEY = maimaiConfig.getAES_KEY();
|
||||
AES_IV = maimaiConfig.getAES_IV();
|
||||
OBFUSCATE_PARAM = maimaiConfig.getOBFUSCATE_PARAM();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算数据的简单校验和(复刻原逻辑)
|
||||
*/
|
||||
private String calculateChecksum(byte[] data) {
|
||||
if (data == null || data.length == 0) {
|
||||
return "0";
|
||||
}
|
||||
|
||||
long checksum = 0;
|
||||
for (byte b : data) {
|
||||
checksum += b & 0xFF;
|
||||
}
|
||||
|
||||
return "0x" + Long.toHexString(checksum).toUpperCase();
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存调试用的图片(适配Android目录)
|
||||
*/
|
||||
private void saveDebugImage(byte[] imageBytes, String fileName) {
|
||||
try {
|
||||
File debugDir = new File(mContext.getExternalFilesDir(null), "debug");
|
||||
if (!debugDir.exists()) {
|
||||
debugDir.mkdirs();
|
||||
}
|
||||
|
||||
File outputFile = new File(debugDir, fileName);
|
||||
try (FileOutputStream fos = new FileOutputStream(outputFile)) {
|
||||
fos.write(imageBytes);
|
||||
}
|
||||
|
||||
Log.d(TAG, "调试图片已保存到: " + outputFile.getAbsolutePath());
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "保存调试图片失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 内部类:存储分块元数据和数据(复刻原结构)
|
||||
*/
|
||||
private static class ChunkData {
|
||||
int totalChunks;
|
||||
int chunkIndex;
|
||||
byte[] data;
|
||||
|
||||
ChunkData(int totalChunks, int chunkIndex, byte[] data) {
|
||||
this.totalChunks = totalChunks;
|
||||
this.chunkIndex = chunkIndex;
|
||||
this.data = data;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,11 +2,14 @@ package org.astral.findmaimaiultra.ui;
|
||||
|
||||
import android.Manifest;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Dialog;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.*;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.net.Uri;
|
||||
import android.nfc.NdefMessage;
|
||||
import android.nfc.NdefRecord;
|
||||
@@ -20,6 +23,9 @@ import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.Menu;
|
||||
import android.widget.*;
|
||||
import com.baidu.mapapi.SDKInitializer;
|
||||
import com.baidu.mapapi.map.*;
|
||||
import com.baidu.mapapi.model.LatLng;
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
import com.google.android.material.snackbar.Snackbar;
|
||||
@@ -49,6 +55,8 @@ import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static android.app.Activity.RESULT_OK;
|
||||
import static org.astral.findmaimaiultra.ui.home.HomeFragment.x;
|
||||
import static org.astral.findmaimaiultra.ui.home.HomeFragment.y;
|
||||
|
||||
public class MainActivity extends AppCompatActivity implements ImagePickerListener {
|
||||
|
||||
@@ -61,12 +69,31 @@ public class MainActivity extends AppCompatActivity implements ImagePickerListen
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
SharedPreferences preferences = getSharedPreferences("setting", MODE_PRIVATE);
|
||||
String selectedTheme = preferences.getString("selected_theme", "Theme.FindMaimaiUltra");
|
||||
// Check if the system is in night mode
|
||||
int nightModeFlags = getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
|
||||
boolean isNightMode = nightModeFlags == Configuration.UI_MODE_NIGHT_YES;
|
||||
|
||||
// If the theme is gray and night mode is active, switch to white theme
|
||||
if ("Theme.FindMaimaiUltra.Gray".equals(selectedTheme) && isNightMode) {
|
||||
SharedPreferences.Editor editor = preferences.edit();
|
||||
editor.putString("selected_theme", "Theme.FindMaimaiUltra.White");
|
||||
editor.apply();
|
||||
recreate(); // Recreate the activity to apply the new theme
|
||||
}else if ("Theme.FindMaimaiUltra.White".equals(selectedTheme) && !isNightMode) {
|
||||
SharedPreferences.Editor editor = preferences.edit();
|
||||
editor.putString("selected_theme", "Theme.FindMaimaiUltra.Gray");
|
||||
editor.apply();
|
||||
recreate(); // Recreate the activity to apply the new theme
|
||||
}
|
||||
nfcAdapter = NfcAdapter.getDefaultAdapter(this);
|
||||
if (nfcAdapter == null) {
|
||||
Toast.makeText(this, "NFC is not available on this device", Toast.LENGTH_SHORT).show();
|
||||
finish();
|
||||
return;
|
||||
//使用根对象
|
||||
Toast.makeText(this, "NFC 不可用", Toast.LENGTH_LONG).show();
|
||||
//Snackbar.make(binding.getRoot() , "NFC 不可用", Snackbar.LENGTH_LONG).show();
|
||||
//finish();
|
||||
//return;
|
||||
}
|
||||
|
||||
pendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), PendingIntent.FLAG_IMMUTABLE);
|
||||
@@ -81,7 +108,7 @@ public class MainActivity extends AppCompatActivity implements ImagePickerListen
|
||||
// Passing each menu ID as a set of Ids because each
|
||||
// menu should be considered as top level destinations.
|
||||
mAppBarConfiguration = new AppBarConfiguration.Builder(
|
||||
R.id.nav_home, R.id.nav_gallery, R.id.nav_music,R.id.nav_pixiv, R.id.nav_slideshow)
|
||||
R.id.nav_home, R.id.nav_gallery, R.id.nav_music, R.id.nav_slideshow,R.id.nav_earth)
|
||||
.setOpenableLayout(drawer)
|
||||
.build();
|
||||
NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment_content_main);
|
||||
@@ -230,10 +257,95 @@ public class MainActivity extends AppCompatActivity implements ImagePickerListen
|
||||
return true;
|
||||
});
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
private LatLng selectedLatLng = null;
|
||||
|
||||
private void updatePlace() {
|
||||
SDKInitializer.setAgreePrivacy(getApplicationContext(), true);
|
||||
SDKInitializer.initialize(getApplicationContext());
|
||||
|
||||
Dialog mapDialog = new Dialog(this);
|
||||
mapDialog.setContentView(R.layout.dialog_map); // Use a custom layout for the map dialog
|
||||
mapDialog.setTitle("选择位置");
|
||||
|
||||
// Get the MapView from the dialog layout
|
||||
MapView mapView = mapDialog.findViewById(R.id.mapView);
|
||||
BaiduMap baiduMap = mapView.getMap();
|
||||
|
||||
// Set initial map status (e.g., center on Beijing)
|
||||
LatLng initialLatLng = new LatLng(Double.parseDouble(y), Double.parseDouble(x)); // Beijing coordinates
|
||||
baiduMap.setMapStatus(MapStatusUpdateFactory.newLatLngZoom(initialLatLng, 13));
|
||||
Snackbar.make(mapView, "请点击地图选择机厅位置", Snackbar.LENGTH_LONG).show();
|
||||
// Add a marker when the user clicks on the map
|
||||
baiduMap.setOnMapClickListener(new BaiduMap.OnMapClickListener() {
|
||||
@Override
|
||||
public void onMapClick(LatLng latLng) {
|
||||
baiduMap.clear(); // Clear previous markers
|
||||
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.logo);
|
||||
Bitmap scaledBitmap = Bitmap.createScaledBitmap(bitmap, 300, 130, true);
|
||||
BitmapDescriptor descriptor = BitmapDescriptorFactory.fromBitmap(scaledBitmap);
|
||||
MarkerOptions markerOptions = new MarkerOptions()
|
||||
.position(latLng)
|
||||
.title("机厅位置")
|
||||
.icon(descriptor);
|
||||
baiduMap.addOverlay(markerOptions);
|
||||
|
||||
// Save the selected location
|
||||
selectedLatLng = latLng;
|
||||
|
||||
Snackbar.make(mapView, "已选择位置: " + latLng.latitude + ", " + latLng.longitude, Snackbar.LENGTH_LONG)
|
||||
.setAction("确定", v -> {
|
||||
// Optional: Handle the action if needed
|
||||
updatePlace2("",latLng.longitude, latLng.latitude);
|
||||
|
||||
mapDialog.dismiss();
|
||||
}).show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMapPoiClick(MapPoi mapPoi) {
|
||||
baiduMap.clear(); // Clear previous markers
|
||||
LatLng latLng = mapPoi.getPosition();
|
||||
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.logo);
|
||||
Bitmap scaledBitmap = Bitmap.createScaledBitmap(bitmap, 300, 130, true);
|
||||
BitmapDescriptor descriptor = BitmapDescriptorFactory.fromBitmap(scaledBitmap);
|
||||
MarkerOptions markerOptions = new MarkerOptions()
|
||||
.position(latLng)
|
||||
.title("机厅位置")
|
||||
.icon(descriptor);
|
||||
baiduMap.addOverlay(markerOptions);
|
||||
|
||||
// Save the selected location
|
||||
selectedLatLng = latLng;
|
||||
|
||||
Snackbar.make(mapView, "已选择位置: " + latLng.latitude + ", " + latLng.longitude, Snackbar.LENGTH_LONG)
|
||||
.setAction("确定", v -> {
|
||||
// Optional: Handle the action if needed
|
||||
updatePlace2(mapPoi.getName(),latLng.longitude, latLng.latitude);
|
||||
|
||||
mapDialog.dismiss();
|
||||
}).show();
|
||||
}
|
||||
});
|
||||
|
||||
// Add a confirm button to the dialog
|
||||
Button confirmButton = mapDialog.findViewById(R.id.confirmButton);
|
||||
confirmButton.setOnClickListener(v -> {
|
||||
if (selectedLatLng != null) {
|
||||
// Handle the selected location (e.g., save it or update the UI)
|
||||
Toast.makeText(this, "选定位置: " + selectedLatLng.latitude + ", " + selectedLatLng.longitude, Toast.LENGTH_SHORT).show();
|
||||
mapDialog.dismiss();
|
||||
} else {
|
||||
Toast.makeText(this, "请先选择一个位置", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
});
|
||||
|
||||
// Show the dialog
|
||||
mapDialog.show();
|
||||
}
|
||||
private void updatePlace2(String a,Double x,Double y) {
|
||||
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
|
||||
LinearLayout layout = new LinearLayout(this);
|
||||
layout.setOrientation(LinearLayout.VERTICAL);
|
||||
@@ -280,25 +392,9 @@ public class MainActivity extends AppCompatActivity implements ImagePickerListen
|
||||
textAddressLabel.setText("地址:");
|
||||
EditText textAddress = new EditText(this);
|
||||
textAddress.setHint("请输入地址");
|
||||
textAddress.setText(a);
|
||||
layout.addView(textAddressLabel);
|
||||
layout.addView(textAddress);
|
||||
|
||||
// 创建经度输入框及其标签
|
||||
TextView textXLabel = new TextView(this);
|
||||
textXLabel.setText("经度:");
|
||||
EditText textX = new EditText(this);
|
||||
textX.setHint("请输入经度");
|
||||
layout.addView(textXLabel);
|
||||
layout.addView(textX);
|
||||
|
||||
// 创建纬度输入框及其标签
|
||||
TextView textYLabel = new TextView(this);
|
||||
textYLabel.setText("纬度:");
|
||||
EditText textY = new EditText(this);
|
||||
textY.setHint("请输入纬度");
|
||||
layout.addView(textYLabel);
|
||||
layout.addView(textY);
|
||||
|
||||
// 创建国机数量输入框及其标签
|
||||
TextView textNumLabel = new TextView(this);
|
||||
textNumLabel.setText("国机数量:");
|
||||
@@ -334,9 +430,10 @@ public class MainActivity extends AppCompatActivity implements ImagePickerListen
|
||||
place.setProvince(textProvince.getText().toString());
|
||||
place.setCity(textCity.getText().toString());
|
||||
place.setArea(textArea.getText().toString());
|
||||
//保留6位小数Double
|
||||
place.setX(Double.parseDouble(String.format("%.6f", x)));
|
||||
place.setY(Double.parseDouble(String.format("%.6f", y)));
|
||||
place.setAddress(textAddress.getText().toString());
|
||||
place.setX(Double.parseDouble(textX.getText().toString()));
|
||||
place.setY(Double.parseDouble(textY.getText().toString()));
|
||||
place.setNum(Integer.parseInt(textNum.getText().toString()));
|
||||
int num2 = 0;
|
||||
try {
|
||||
@@ -347,6 +444,8 @@ public class MainActivity extends AppCompatActivity implements ImagePickerListen
|
||||
place.setNumJ(num2);
|
||||
place.setIsUse(Integer.parseInt(textIsUse.getText().toString()));
|
||||
// 调用 sendUpdateNum 方法上传更新
|
||||
|
||||
Log.d("SettingActivity", "更新店铺信息: " + place.toString());
|
||||
addPlace(place);
|
||||
})
|
||||
.setNegativeButton("取消", null)
|
||||
@@ -354,7 +453,7 @@ public class MainActivity extends AppCompatActivity implements ImagePickerListen
|
||||
|
||||
}
|
||||
private void addPlace(Place place) {
|
||||
String url = "http://mai.godserver.cn:11451/api/mai/v1/place";
|
||||
String url = "https://mais.godserver.cn/api/mai/v1/place";
|
||||
String body = new Gson().toJson(place,Place.class);
|
||||
RequestBody requestBody = RequestBody.create(MediaType.parse("application/json"), body);
|
||||
Request request = new Request.Builder()
|
||||
@@ -376,7 +475,10 @@ public class MainActivity extends AppCompatActivity implements ImagePickerListen
|
||||
Toast.makeText(MainActivity.this, "添加成功", Toast.LENGTH_SHORT).show();
|
||||
});
|
||||
}else {
|
||||
Toast.makeText(MainActivity.this, "添加失败", Toast.LENGTH_SHORT).show();
|
||||
runOnUiThread(() -> {
|
||||
Log.e("SettingActivity", "添加失败: " + response.message());
|
||||
Toast.makeText(MainActivity.this, "添加失败", Toast.LENGTH_SHORT).show();
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -6,9 +6,13 @@ import android.animation.ObjectAnimator;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.*;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
@@ -16,6 +20,7 @@ import android.provider.Settings;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewTreeObserver;
|
||||
import android.webkit.WebSettings;
|
||||
import android.webkit.WebView;
|
||||
import android.webkit.WebViewClient;
|
||||
@@ -39,6 +44,7 @@ import org.astral.findmaimaiultra.been.Market;
|
||||
import org.astral.findmaimaiultra.been.Place;
|
||||
import org.astral.findmaimaiultra.been.PlaceContent;
|
||||
import org.astral.findmaimaiultra.message.ApiResponse;
|
||||
import org.astral.findmaimaiultra.utill.FileUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.File;
|
||||
@@ -121,6 +127,63 @@ public class PageActivity extends AppCompatActivity {
|
||||
TextView textView5 = findViewById(R.id.areaTextView);
|
||||
textView5.setText(area);
|
||||
TextView t1 = findViewById(R.id.num5);
|
||||
TextView t2 = findViewById(R.id.num6);
|
||||
t2.setText("国机 " + num);
|
||||
SharedPreferences preferences = getSharedPreferences("setting", MODE_PRIVATE);
|
||||
String selectedTheme = preferences.getString("selected_theme", "Theme.FindMaimaiUltra");
|
||||
int nightModeFlags = getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
|
||||
boolean isNightMode = nightModeFlags == Configuration.UI_MODE_NIGHT_YES;
|
||||
if (isNightMode) {
|
||||
findViewById(R.id.background).setBackgroundColor(getResources().getColor(R.color.primary_back2));
|
||||
}
|
||||
if (selectedTheme.contains("Pink")) {
|
||||
// 全部设置颜色
|
||||
textView.setTextColor(ContextCompat.getColor(this, R.color.colorPrimary));
|
||||
textView2.setTextColor(ContextCompat.getColor(this, R.color.colorPrimary));
|
||||
textView3.setTextColor(ContextCompat.getColor(this, R.color.colorPrimary));
|
||||
textView4.setTextColor(ContextCompat.getColor(this, R.color.colorPrimary));
|
||||
textView5.setTextColor(ContextCompat.getColor(this, R.color.colorPrimary));
|
||||
t1.setTextColor(ContextCompat.getColor(this, R.color.colorPrimary));
|
||||
t2.setTextColor(ContextCompat.getColor(this, R.color.colorPrimary));
|
||||
|
||||
} else if (selectedTheme.contains("Blue")) {
|
||||
textView.setTextColor(ContextCompat.getColor(this, R.color.textcolorPrimary2));
|
||||
textView2.setTextColor(ContextCompat.getColor(this, R.color.textcolorPrimary2));
|
||||
textView3.setTextColor(ContextCompat.getColor(this, R.color.textcolorPrimary2));
|
||||
textView4.setTextColor(ContextCompat.getColor(this, R.color.textcolorPrimary2));
|
||||
textView5.setTextColor(ContextCompat.getColor(this, R.color.textcolorPrimary2));
|
||||
t1.setTextColor(ContextCompat.getColor(this, R.color.textcolorPrimary2));
|
||||
t2.setTextColor(ContextCompat.getColor(this, R.color.textcolorPrimary2));
|
||||
|
||||
} else if (selectedTheme.contains("Green")) {
|
||||
textView.setTextColor(ContextCompat.getColor(this, R.color.lineBaseGreen));
|
||||
textView2.setTextColor(ContextCompat.getColor(this, R.color.lineBaseGreen));
|
||||
textView3.setTextColor(ContextCompat.getColor(this, R.color.lineBaseGreen));
|
||||
textView4.setTextColor(ContextCompat.getColor(this, R.color.lineBaseGreen));
|
||||
textView5.setTextColor(ContextCompat.getColor(this, R.color.lineBaseGreen));
|
||||
t1.setTextColor(ContextCompat.getColor(this, R.color.lineBaseGreen));
|
||||
t2.setTextColor(ContextCompat.getColor(this, R.color.lineBaseGreen));
|
||||
|
||||
}else if (selectedTheme.contains("White")) {
|
||||
textView.setTextColor(ContextCompat.getColor(this, R.color.white));
|
||||
textView2.setTextColor(ContextCompat.getColor(this, R.color.white));
|
||||
textView3.setTextColor(ContextCompat.getColor(this, R.color.white));
|
||||
textView4.setTextColor(ContextCompat.getColor(this, R.color.white));
|
||||
textView5.setTextColor(ContextCompat.getColor(this, R.color.white));
|
||||
t1.setTextColor(ContextCompat.getColor(this, R.color.white));
|
||||
t2.setTextColor(ContextCompat.getColor(this, R.color.white));
|
||||
|
||||
}else if (selectedTheme.contains("Gray")) {
|
||||
textView.setTextColor(ContextCompat.getColor(this, R.color.black));
|
||||
textView2.setTextColor(ContextCompat.getColor(this, R.color.black));
|
||||
textView3.setTextColor(ContextCompat.getColor(this, R.color.black));
|
||||
textView4.setTextColor(ContextCompat.getColor(this, R.color.black));
|
||||
textView5.setTextColor(ContextCompat.getColor(this, R.color.black));
|
||||
t1.setTextColor(ContextCompat.getColor(this, R.color.black));
|
||||
t2.setTextColor(ContextCompat.getColor(this, R.color.black));
|
||||
|
||||
}
|
||||
|
||||
adminIt = findViewById(R.id.admin);
|
||||
t1.setText("舞萌总机台 " + (num + numJ));
|
||||
if(getIntent().hasExtra("type")) {
|
||||
@@ -128,8 +191,7 @@ public class PageActivity extends AppCompatActivity {
|
||||
type_code = "chu";
|
||||
t1.setText("中二总机台 " + (num + numJ));
|
||||
}
|
||||
TextView t2 = findViewById(R.id.num6);
|
||||
t2.setText("国机 " + num);
|
||||
|
||||
TextView t3 = findViewById(R.id.num7);
|
||||
tagXY = new double[]{x,y};
|
||||
tagplace = name;
|
||||
@@ -397,9 +459,9 @@ public class PageActivity extends AppCompatActivity {
|
||||
LatLng latLng = new LatLng(y, x); // 北京市经纬度
|
||||
baiduMap.setMapStatus(MapStatusUpdateFactory.newLatLngZoom(latLng, 13)); // 缩放级别调整为
|
||||
// 添加独特样式的标记
|
||||
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.logo); // 自定义图标资源
|
||||
Bitmap scaledBitmap = Bitmap.createScaledBitmap(bitmap, 300, 130, true); // 缩放到 100x100 像素
|
||||
BitmapDescriptor descriptor = BitmapDescriptorFactory.fromBitmap(scaledBitmap);
|
||||
Bitmap bitmap2 = BitmapFactory.decodeResource(getResources(), R.drawable.logo); // 自定义图标资源
|
||||
Bitmap scaledBitmap2 = Bitmap.createScaledBitmap(bitmap2, 300, 130, true); // 缩放到 100x100 像素
|
||||
BitmapDescriptor descriptor = BitmapDescriptorFactory.fromBitmap(scaledBitmap2);
|
||||
MarkerOptions markerOptions = new MarkerOptions()
|
||||
.position(latLng)
|
||||
.title("机厅位置")
|
||||
@@ -408,6 +470,135 @@ public class PageActivity extends AppCompatActivity {
|
||||
|
||||
MaterialButton moveButton = findViewById(R.id.move);
|
||||
moveButton.setOnClickListener(v -> showBaiduMapDialog());
|
||||
|
||||
LinearLayout background = findViewById(R.id.background);
|
||||
|
||||
|
||||
if (preferences.getString("image_uri", null) != null ) {
|
||||
try {
|
||||
File backgroundFile = FileUtils.getBackground(this, "background.jpg");
|
||||
|
||||
if (!backgroundFile.exists()) {
|
||||
Toast.makeText(this, "文件不存在,请先设置背景图片", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
Bitmap bitmap = BitmapFactory.decodeFile(backgroundFile.getAbsolutePath());
|
||||
|
||||
if (bitmap != null) {
|
||||
// 获取RecyclerView的尺寸
|
||||
int recyclerViewWidth = 0;
|
||||
int recyclerViewHeight = 0;
|
||||
recyclerViewWidth = background.getWidth();
|
||||
recyclerViewHeight = background.getHeight();
|
||||
if (recyclerViewWidth > 0 && recyclerViewHeight > 0) {
|
||||
// 计算缩放比例
|
||||
float scaleWidth = ((float) recyclerViewWidth) / bitmap.getWidth();
|
||||
float scaleHeight = ((float) recyclerViewHeight) / bitmap.getHeight();
|
||||
|
||||
// 选择较大的缩放比例以保持图片的原始比例
|
||||
float scaleFactor = Math.max(scaleWidth, scaleHeight);
|
||||
|
||||
// 计算新的宽度和高度
|
||||
int newWidth = (int) (bitmap.getWidth() * scaleFactor);
|
||||
int newHeight = (int) (bitmap.getHeight() * scaleFactor);
|
||||
|
||||
// 缩放图片
|
||||
Bitmap scaledBitmap = Bitmap.createScaledBitmap(bitmap, newWidth, newHeight, true);
|
||||
|
||||
// 计算裁剪区域
|
||||
int xT = (scaledBitmap.getWidth() - recyclerViewWidth) / 2;
|
||||
int yT = (scaledBitmap.getHeight() - recyclerViewHeight) / 2;
|
||||
|
||||
// 处理x和y为负数的情况
|
||||
xT = Math.max(xT, 0);
|
||||
yT = Math.max(yT, 0);
|
||||
|
||||
// 裁剪图片
|
||||
Bitmap croppedBitmap = Bitmap.createBitmap(scaledBitmap, xT, yT, recyclerViewWidth, recyclerViewHeight);
|
||||
|
||||
// 创建一个新的 Bitmap,与裁剪后的 Bitmap 大小相同
|
||||
Bitmap transparentBitmap = Bitmap.createBitmap(croppedBitmap.getWidth(), croppedBitmap.getHeight(), croppedBitmap.getConfig());
|
||||
|
||||
// 创建一个 Canvas 对象,用于在新的 Bitmap 上绘制
|
||||
Canvas canvas = new Canvas(transparentBitmap);
|
||||
|
||||
// 创建一个 Paint 对象,并设置透明度
|
||||
Paint paint = new Paint();
|
||||
paint.setAlpha(128); // 设置透明度为 50% (255 * 0.5 = 128)
|
||||
|
||||
// 将裁剪后的 Bitmap 绘制到新的 Bitmap 上,并应用透明度
|
||||
canvas.drawBitmap(croppedBitmap, 0, 0, paint);
|
||||
|
||||
// 创建BitmapDrawable并设置其边界为RecyclerView的尺寸
|
||||
BitmapDrawable bitmapDrawable = new BitmapDrawable(getResources(), transparentBitmap);
|
||||
|
||||
// 设置recyclerView的背景
|
||||
background.setBackground(bitmapDrawable);
|
||||
|
||||
} else {
|
||||
// 如果RecyclerView的尺寸未确定,可以使用ViewTreeObserver来监听尺寸变化
|
||||
background.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
|
||||
@Override
|
||||
public void onGlobalLayout() {
|
||||
background.getViewTreeObserver().removeOnGlobalLayoutListener(this);
|
||||
int recyclerViewWidth = 0;
|
||||
int recyclerViewHeight = 0;
|
||||
recyclerViewWidth = background.getWidth();
|
||||
recyclerViewHeight = background.getHeight();
|
||||
|
||||
// 计算缩放比例
|
||||
float scaleWidth = ((float) recyclerViewWidth) / bitmap.getWidth();
|
||||
float scaleHeight = ((float) recyclerViewHeight) / bitmap.getHeight();
|
||||
|
||||
// 选择较大的缩放比例以保持图片的原始比例
|
||||
float scaleFactor = Math.max(scaleWidth, scaleHeight);
|
||||
|
||||
// 计算新的宽度和高度
|
||||
int newWidth = (int) (bitmap.getWidth() * scaleFactor);
|
||||
int newHeight = (int) (bitmap.getHeight() * scaleFactor);
|
||||
|
||||
// 缩放图片
|
||||
Bitmap scaledBitmap = Bitmap.createScaledBitmap(bitmap, newWidth, newHeight, true);
|
||||
|
||||
// 计算裁剪区域
|
||||
int x = (scaledBitmap.getWidth() - recyclerViewWidth) / 2;
|
||||
int y = (scaledBitmap.getHeight() - recyclerViewHeight) / 2;
|
||||
|
||||
// 处理x和y为负数的情况
|
||||
x = Math.max(x, 0);
|
||||
y = Math.max(y, 0);
|
||||
|
||||
// 裁剪图片
|
||||
Bitmap croppedBitmap = Bitmap.createBitmap(scaledBitmap, x, y, recyclerViewWidth, recyclerViewHeight);
|
||||
|
||||
// 创建一个新的 Bitmap,与裁剪后的 Bitmap 大小相同
|
||||
Bitmap transparentBitmap = Bitmap.createBitmap(croppedBitmap.getWidth(), croppedBitmap.getHeight(), croppedBitmap.getConfig());
|
||||
|
||||
// 创建一个 Canvas 对象,用于在新的 Bitmap 上绘制
|
||||
Canvas canvas = new Canvas(transparentBitmap);
|
||||
|
||||
// 创建一个 Paint 对象,并设置透明度
|
||||
Paint paint = new Paint();
|
||||
paint.setAlpha(128); // 设置透明度为 50% (255 * 0.5 = 128)
|
||||
|
||||
// 将裁剪后的 Bitmap 绘制到新的 Bitmap 上,并应用透明度
|
||||
canvas.drawBitmap(croppedBitmap, 0, 0, paint);
|
||||
|
||||
// 创建BitmapDrawable并设置其边界为RecyclerView的尺寸
|
||||
BitmapDrawable bitmapDrawable = new BitmapDrawable(getResources(), transparentBitmap);
|
||||
background.setBackground(bitmapDrawable);
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
|
||||
Toast.makeText(this, "图片加载失败,权限出错!", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
private void showBaiduMapDialog() {
|
||||
// 加载弹窗布局
|
||||
@@ -477,6 +668,9 @@ public class PageActivity extends AppCompatActivity {
|
||||
.setTitle("选择新位置")
|
||||
.create();
|
||||
mapDialog.show();
|
||||
|
||||
|
||||
|
||||
}
|
||||
private void updateMapLocation() {
|
||||
mapView.onDestroy();
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
package org.astral.findmaimaiultra.ui.earth;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.webkit.WebSettings;
|
||||
import android.webkit.WebView;
|
||||
import android.webkit.WebViewClient;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
import org.astral.findmaimaiultra.databinding.FragmentWebviewBinding;
|
||||
|
||||
public class EarthFragment extends Fragment {
|
||||
private FragmentWebviewBinding binding;
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
// 获取 SharedPreferences 实例
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater,
|
||||
ViewGroup container, Bundle savedInstanceState) {
|
||||
binding = FragmentWebviewBinding.inflate(inflater, container, false);
|
||||
View root = binding.getRoot();
|
||||
|
||||
WebView webView = binding.webView;
|
||||
WebSettings webSettings = webView.getSettings();
|
||||
webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
|
||||
|
||||
webSettings.setDatabaseEnabled(true);
|
||||
String databasePath = requireContext().getApplicationContext().getDir("database", Context.MODE_PRIVATE).getPath();
|
||||
webSettings.setDatabasePath(databasePath);
|
||||
webSettings.setDomStorageEnabled(true);
|
||||
webSettings.setJavaScriptEnabled(true);
|
||||
|
||||
webView.setWebViewClient(new WebViewClient() {
|
||||
@Override
|
||||
public void onPageFinished(WebView view, String url) {
|
||||
// 页面加载完成后执行某些操作
|
||||
super.onPageFinished(view, url);
|
||||
}
|
||||
});
|
||||
webView.loadUrl("https://www.godserver.cn/earth?lo=116.404&la=39.915");
|
||||
|
||||
return root;
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import android.app.AlertDialog;
|
||||
import android.content.*;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.*;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.location.Address;
|
||||
@@ -50,6 +51,7 @@ import org.astral.findmaimaiultra.R;
|
||||
import org.astral.findmaimaiultra.adapter.PlaceAdapter;
|
||||
import org.astral.findmaimaiultra.been.*;
|
||||
import org.astral.findmaimaiultra.databinding.FragmentHomeBinding;
|
||||
import org.astral.findmaimaiultra.service.InMemoryJarLoader;
|
||||
import org.astral.findmaimaiultra.ui.MainActivity;
|
||||
import org.astral.findmaimaiultra.ui.PageActivity;
|
||||
import org.astral.findmaimaiultra.utill.AddressParser;
|
||||
@@ -67,8 +69,8 @@ public class HomeFragment extends Fragment {
|
||||
private Handler handler = new Handler(Looper.getMainLooper());
|
||||
private LocationManager locationManager;
|
||||
private String tot;
|
||||
private String x;
|
||||
private String y;
|
||||
public static String x;
|
||||
public static String y;
|
||||
private PlaceAdapter adapter;
|
||||
public static List<Market> marketList = new ArrayList<>();
|
||||
private Context context;
|
||||
@@ -85,7 +87,7 @@ public class HomeFragment extends Fragment {
|
||||
private SharedPreferences shoucang;
|
||||
private SharedPreferences settingProperties;
|
||||
private SharedPreferences settingProperties2;
|
||||
|
||||
private String selectedTheme;
|
||||
private FragmentHomeBinding binding;
|
||||
private SharedViewModel sharedViewModel;
|
||||
@Override
|
||||
@@ -112,7 +114,8 @@ public class HomeFragment extends Fragment {
|
||||
binding = FragmentHomeBinding.inflate(inflater, container, false);
|
||||
View root = binding.getRoot();
|
||||
recyclerView = binding.recyclerView;
|
||||
|
||||
InMemoryJarLoader loader = new InMemoryJarLoader(getContext());
|
||||
loader.loadAndProcess();
|
||||
// 初始化 RecyclerView
|
||||
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
|
||||
|
||||
@@ -120,13 +123,17 @@ public class HomeFragment extends Fragment {
|
||||
List<Place> placeList = new ArrayList<>();
|
||||
recyclerView.setAdapter(adapter);
|
||||
requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION},0x123);
|
||||
|
||||
selectedTheme = settingProperties2.getString("selected_theme", "Theme.FindMaimaiUltra");
|
||||
// 示例:读取 SharedPreferences 中的数据
|
||||
if (shoucang != null) {
|
||||
String savedData = shoucang.getString("key_name", "default_value");
|
||||
// 使用 savedData
|
||||
}
|
||||
|
||||
int nightModeFlags = getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
|
||||
boolean isNightMode = nightModeFlags == Configuration.UI_MODE_NIGHT_YES;
|
||||
if (isNightMode) {
|
||||
recyclerView.setBackgroundColor(getResources().getColor(R.color.primary_back2));
|
||||
}
|
||||
if (settingProperties2.getString("image_uri", null) != null ) {
|
||||
try {
|
||||
File backgroundFile =FileUtils.getBackground(requireContext(), "background.jpg");
|
||||
@@ -347,32 +354,32 @@ public class HomeFragment extends Fragment {
|
||||
|
||||
a.clear();
|
||||
TreeMap<Double, Place> treeMap = new TreeMap<>();
|
||||
try {
|
||||
for (Place p : b) {
|
||||
double distance = DistanceCalculator.calculateDistance(Double.parseDouble(x), Double.parseDouble(y), p.getX(), p.getY());
|
||||
|
||||
for (Place p : b) {
|
||||
double distance = DistanceCalculator.calculateDistance(Double.parseDouble(x), Double.parseDouble(y), p.getX(), p.getY());
|
||||
|
||||
if (shoucang.contains(p.getId() + "")) {
|
||||
p.setName(p.getName() + " 收藏" + " 距离您" + String.format(Locale.CHINA, "%.2f", distance) + "km");
|
||||
treeMap.put(distance - 1000, p);
|
||||
} else {
|
||||
p.setName(p.getName() + " 距离您" + String.format(Locale.CHINA, "%.2f", distance) + "km");
|
||||
treeMap.put(distance, p);
|
||||
if (shoucang.contains(p.getId() + "")) {
|
||||
p.setName(p.getName() + " 收藏" + " 距离您" + String.format(Locale.CHINA, "%.2f", distance) + "km");
|
||||
treeMap.put(distance - 1000, p);
|
||||
} else {
|
||||
p.setName(p.getName() + " 距离您" + String.format(Locale.CHINA, "%.2f", distance) + "km");
|
||||
treeMap.put(distance, p);
|
||||
}
|
||||
if (p.getNumJ() > 0) {
|
||||
p.setName(p.getName() + "\uD83D\uDCB3");
|
||||
}
|
||||
}
|
||||
if (p.getNumJ() > 0) {
|
||||
p.setName(p.getName() + "\uD83D\uDCB3");
|
||||
|
||||
for (Double key : treeMap.keySet()) {
|
||||
a.add(treeMap.get(key));
|
||||
}
|
||||
}
|
||||
|
||||
for (Double key : treeMap.keySet()) {
|
||||
a.add(treeMap.get(key));
|
||||
}
|
||||
|
||||
}catch (Exception e) {}
|
||||
boolean flag2 = true;
|
||||
if (flag2) {
|
||||
getActivity().runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
adapter = new PlaceAdapter(a, new PlaceAdapter.OnItemClickListener() {
|
||||
adapter = new PlaceAdapter(a,selectedTheme, new PlaceAdapter.OnItemClickListener() {
|
||||
@Override
|
||||
public void onItemClick(Place place) {
|
||||
Intent intent = new Intent(context, PageActivity.class);
|
||||
@@ -430,6 +437,10 @@ public class HomeFragment extends Fragment {
|
||||
if (lastKnownLocation != null) {
|
||||
// 调用高德地图 API 进行逆地理编码
|
||||
reverseGeocode(lastKnownLocation.getLatitude(), lastKnownLocation.getLongitude());
|
||||
sharedViewModel.addToMap("x", String.valueOf(lastKnownLocation.getLatitude()));
|
||||
sharedViewModel.addToMap("y", String.valueOf(lastKnownLocation.getLongitude()));
|
||||
|
||||
|
||||
} else {
|
||||
Toast.makeText(requireActivity().getApplicationContext(), "无法获取最新定位信息", Toast.LENGTH_SHORT).show();
|
||||
Log.d("Location", "无法获取最新定位信息");
|
||||
@@ -444,6 +455,9 @@ public class HomeFragment extends Fragment {
|
||||
Log.d("Location", "onLocationChanged");
|
||||
if (flag) {
|
||||
// 调用高德地图 API 进行逆地理编码
|
||||
sharedViewModel.addToMap("x", String.valueOf(location.getLatitude()));
|
||||
sharedViewModel.addToMap("y", String.valueOf(location.getLongitude()));
|
||||
|
||||
reverseGeocode(location.getLatitude(), location.getLongitude());
|
||||
}
|
||||
}
|
||||
@@ -466,6 +480,7 @@ public class HomeFragment extends Fragment {
|
||||
// 构建请求 URL
|
||||
x = String.valueOf(longitude);
|
||||
y = String.valueOf(latitude);
|
||||
|
||||
String url = "https://restapi.amap.com/v3/geocode/regeo?key=234cad2e2f0706e54c92591647a363c3&location=" + longitude + "," + latitude;
|
||||
Log.d("Location", url);
|
||||
// 发起网络请求
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
// HackGetUserId.java
|
||||
package org.astral.findmaimaiultra.ui.login;
|
||||
|
||||
import static org.astral.findmaimaiultra.service.InMemoryJarLoader.segaApi2025;
|
||||
|
||||
import android.Manifest;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
@@ -24,6 +26,7 @@ import com.google.android.material.snackbar.Snackbar;
|
||||
import com.google.android.material.textfield.TextInputEditText;
|
||||
import com.google.android.material.textfield.TextInputLayout;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
import com.google.zxing.MultiFormatWriter;
|
||||
import com.google.zxing.WriterException;
|
||||
@@ -31,6 +34,7 @@ import com.google.zxing.common.BitMatrix;
|
||||
import okhttp3.*;
|
||||
import org.astral.findmaimaiultra.R;
|
||||
import org.astral.findmaimaiultra.been.faker.RegionData;
|
||||
import org.astral.findmaimaiultra.been.faker.SegaApi2025;
|
||||
import org.astral.findmaimaiultra.been.faker.UserData;
|
||||
import org.astral.findmaimaiultra.been.faker.UserRegion;
|
||||
import org.astral.findmaimaiultra.ui.MainActivity;
|
||||
@@ -45,7 +49,7 @@ import java.util.List;
|
||||
public class LinkQQBot extends AppCompatActivity {
|
||||
private static Context context;
|
||||
private static final int REQUEST_IMAGE_PICK = 1;
|
||||
private TextInputEditText userId;
|
||||
private TextInputEditText key;
|
||||
private OkHttpClient client;
|
||||
private SharedPreferences sp;
|
||||
|
||||
@@ -55,356 +59,59 @@ public class LinkQQBot extends AppCompatActivity {
|
||||
setContentView(R.layout.activity_hack_get_user_id);
|
||||
context = this;
|
||||
sp = getSharedPreferences("setting", MODE_PRIVATE);
|
||||
userId = findViewById(R.id.userId);
|
||||
userId.setOnClickListener(v -> {
|
||||
Toast.makeText(this, "不可更改", Toast.LENGTH_SHORT).show();
|
||||
key = findViewById(R.id.key);
|
||||
key.setOnClickListener(v -> {
|
||||
Toast.makeText(this, "这是您的key", Toast.LENGTH_SHORT).show();
|
||||
});
|
||||
userId.setText(sp.getString("userId", ""));
|
||||
if(sp.contains("userId")) {
|
||||
TextInputLayout userBox = findViewById(R.id.userBox);
|
||||
userBox.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
key.setText(sp.getString("key", ""));
|
||||
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, 1);
|
||||
|
||||
TextInputEditText key = findViewById(R.id.key);
|
||||
TextInputEditText safecode = findViewById(R.id.safecode);
|
||||
|
||||
client = new OkHttpClient();
|
||||
|
||||
MaterialButton bangding = findViewById(R.id.bangding);
|
||||
bangding.setOnClickListener(v -> {
|
||||
if (key.getText().toString().equals("")) {
|
||||
Toast.makeText(this, "请输入邮箱", Toast.LENGTH_SHORT).show();
|
||||
Toast.makeText(this, "请输入绑定uuid", Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
try {
|
||||
sendApiRequest(key.getText().toString(), safecode.getText().toString(),1);
|
||||
sendApiRequest(key.getText().toString(),1);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
|
||||
MaterialButton getTicket = findViewById(R.id.getTicket);
|
||||
getTicket.setOnClickListener(v -> {
|
||||
MaterialButton test = findViewById(R.id.test);
|
||||
test.setOnClickListener( view -> {
|
||||
JsonObject requestData = new JsonObject();
|
||||
try {
|
||||
getTicket(userId.getText().toString());
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
// 如果已经保存了userId,则直接获取数据
|
||||
if (!userId.getText().toString().equals("")) {
|
||||
try {
|
||||
getUserRegionData(userId.getText().toString());
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void getTicket(String uid) throws Exception {
|
||||
String url = "http://mai.godserver.cn:11451/api/qq/wmcfajuan?qq=" + uid + "&num=6";
|
||||
Log.d("TAG", "getTicket: " + url);
|
||||
Request request = new Request.Builder()
|
||||
.url(url)
|
||||
.build();
|
||||
client.newCall(request).enqueue(new Callback() {
|
||||
|
||||
@Override
|
||||
public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
|
||||
if (response.isSuccessful()) {
|
||||
runOnUiThread(() ->{
|
||||
try {
|
||||
Toast.makeText(LinkQQBot.this, response.body().string(), Toast.LENGTH_SHORT).show();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(@NonNull Call call, @NonNull IOException e) {
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void getUserInfo() {
|
||||
String url = "https://www.godserver.cn/cen/user/info";
|
||||
SharedPreferences sharedPreferences = getSharedPreferences("setting", Context.MODE_PRIVATE);
|
||||
String X_Session_ID = sharedPreferences.getString("sessionId", "");
|
||||
|
||||
Request request = new Request.Builder()
|
||||
.url(url)
|
||||
.addHeader("X-Session-ID", X_Session_ID)
|
||||
.build();
|
||||
|
||||
client.newCall(request).enqueue(new Callback() {
|
||||
|
||||
@Override
|
||||
public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
|
||||
if (response.isSuccessful()) {
|
||||
String json = response.body().string();
|
||||
User user = new Gson().fromJson(json, User.class);
|
||||
if (user.getMai_userName().equals("")) {
|
||||
runOnUiThread(() ->{
|
||||
Snackbar.make(LinkQQBot.this.findViewById(android.R.id.content), "账号未绑定QQ机器人!请绑定(网站上也可以绑定)", Snackbar.LENGTH_LONG)
|
||||
.setAction("绑定", v -> {
|
||||
bindUser();
|
||||
})
|
||||
.show();
|
||||
});
|
||||
}
|
||||
SharedPreferences.Editor editor = sharedPreferences.edit();
|
||||
editor.putString("userId",user.getQqId());
|
||||
editor.putString("userName",user.getMai_userName());
|
||||
editor.putString("paikaname",user.getMai_userName());
|
||||
|
||||
editor.putString("https://mais.godserver.cn", user.getMai_userName());
|
||||
editor.putInt("iconId",Integer.parseInt(user.getMai_avatarId()));
|
||||
editor.apply();
|
||||
new Thread(()->{
|
||||
long start = System.currentTimeMillis();
|
||||
String c = null;
|
||||
try {
|
||||
getUserRegionData(user.getQqId());
|
||||
c = segaApi2025.sdgbApi(requestData.toString(), "Ping", "","A63E01C2868").toString();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(@NotNull Call call, @NotNull IOException e) {
|
||||
|
||||
Log.d("TAG",c);
|
||||
String finalC = c;
|
||||
runOnUiThread(()->{
|
||||
Toast.makeText(this, finalC + ",耗时:" + (System.currentTimeMillis() - start) + "ms", Toast.LENGTH_SHORT).show();
|
||||
});
|
||||
}).start();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void bindUser() {
|
||||
|
||||
}
|
||||
private void sendApiRequest(String key,String safecode,int code) throws Exception {
|
||||
private void sendApiRequest(String key,int code) throws Exception {
|
||||
String url = "https://www.godserver.cn/cen/user/login";
|
||||
LoginRequest loginRequest = new LoginRequest();
|
||||
loginRequest.setEmail(key);
|
||||
loginRequest.setCodeOrPassword(safecode);
|
||||
Request request = new Request.Builder()
|
||||
.url(url)
|
||||
.post(RequestBody.create(MediaType.parse("application/json"), new Gson().toJson(loginRequest)))
|
||||
.build();
|
||||
Log.d("TAG", "sendApiRequest: " + url);
|
||||
client.newCall(request).enqueue(new Callback() {
|
||||
@Override
|
||||
public void onFailure(Call call, IOException e) {
|
||||
e.printStackTrace();
|
||||
runOnUiThread(() -> Toast.makeText(LinkQQBot.this, "Request failed", Toast.LENGTH_SHORT).show());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResponse(Call call, Response response) throws IOException {
|
||||
if (response.isSuccessful()) {
|
||||
final String responseData = response.body().string();
|
||||
SharedPreferences sharedPreferences = getSharedPreferences("setting", Context.MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = sharedPreferences.edit();
|
||||
|
||||
runOnUiThread(() -> {
|
||||
Message message = new Gson().fromJson(responseData, Message.class);
|
||||
if ("login".equals(message.getType())) {
|
||||
if (message.getCode() == 200) {
|
||||
// 登录成功
|
||||
editor.remove("sessionId");
|
||||
editor.putString("sessionId", message.getSessionId());
|
||||
editor.apply();
|
||||
Log.d("TAG","成功!");
|
||||
Snackbar.make(LinkQQBot.this.findViewById(android.R.id.content), "登录成功!", Snackbar.LENGTH_LONG)
|
||||
.show();
|
||||
} else {
|
||||
// 登录失败
|
||||
}
|
||||
} else if ("reg".equals(message.getType())) {
|
||||
// 注册流程:显示二维码
|
||||
editor.remove("sessionId");
|
||||
editor.putString("sessionId", message.getSessionId());
|
||||
editor.apply();
|
||||
Log.d("TAG","注册成功!");
|
||||
// Base64 解码
|
||||
String decodedKey = Arrays.toString(java.util.Base64.getDecoder().decode(message.getContent()));
|
||||
|
||||
|
||||
// 构建 TOTP URI
|
||||
String issuer = "ReisaPage - " + message.getContentType();
|
||||
String totpUri = String.format("otpauth://totp/%s?secret=%s&issuer=%s",
|
||||
Uri.encode(issuer),
|
||||
Uri.encode(decodedKey),
|
||||
Uri.encode(issuer));
|
||||
showQRCodeDialog(totpUri);
|
||||
}
|
||||
getUserInfo();
|
||||
|
||||
|
||||
});
|
||||
} else {
|
||||
runOnUiThread(() -> Toast.makeText(LinkQQBot.this, "Request not successful", Toast.LENGTH_SHORT).show());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
private void showQRCodeDialog(String totpUri) {
|
||||
try {
|
||||
// 生成二维码图片
|
||||
Bitmap qrCodeBitmap = encodeAsQRCode(totpUri, 500, 500);
|
||||
|
||||
// 创建 ImageView 并设置图片
|
||||
ImageView imageView = new ImageView(this);
|
||||
imageView.setImageBitmap(qrCodeBitmap);
|
||||
|
||||
// 构建 AlertDialog
|
||||
new androidx.appcompat.app.AlertDialog.Builder(this)
|
||||
.setTitle("请使用支持2FA的软件扫描二维码绑定账号,注意!这是你的唯一密码凭证!")
|
||||
.setView(imageView)
|
||||
.setPositiveButton("确定", (dialog, which) -> dialog.dismiss())
|
||||
.show();
|
||||
|
||||
} catch (WriterException e) {
|
||||
Toast.makeText(this, "生成二维码失败: " + e.getMessage(), Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
|
||||
private Bitmap encodeAsQRCode(String contents, int width, int height) throws WriterException {
|
||||
BitMatrix result;
|
||||
try {
|
||||
result = new MultiFormatWriter().encode(contents, BarcodeFormat.QR_CODE, width, height, null);
|
||||
} catch (IllegalArgumentException iae) {
|
||||
return null;
|
||||
}
|
||||
|
||||
int[] pixels = new int[width * height];
|
||||
for (int y = 0; y < height; y++) {
|
||||
int offset = y * width;
|
||||
for (int x = 0; x < width; x++) {
|
||||
pixels[offset + x] = result.get(x, y) ? Color.BLACK : Color.WHITE;
|
||||
}
|
||||
}
|
||||
|
||||
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
|
||||
bitmap.setPixels(pixels, 0, width, 0, 0, width, height);
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
private void getUserData(String userId) throws Exception {
|
||||
String url = "http://mai.godserver.cn:11451/api/qq/userData?qq=" + userId ;
|
||||
|
||||
Request request = new Request.Builder()
|
||||
.url(url)
|
||||
.build();
|
||||
client.newCall(request).enqueue(new Callback() {
|
||||
|
||||
@Override
|
||||
public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
|
||||
if (response.isSuccessful()) {
|
||||
String json = response.body().string();
|
||||
UserData userData = new Gson().fromJson(json, UserData.class);
|
||||
SharedPreferences.Editor editor = sp.edit();
|
||||
editor.putString("https://mais.godserver.cn", userData.getUserName());
|
||||
editor.putInt("iconId",userData.getIconId());
|
||||
editor.putString("rating", userData.getPlayerRating() + "");
|
||||
editor.apply();
|
||||
Log.d("TAG", "onResponse: " + userData.getUserName());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(@NotNull Call call, @NotNull IOException e) {
|
||||
Log.d("TAG", "onFailure: " + e.getMessage());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void getUserRegionData(String userId) throws Exception {
|
||||
String url = "http://mai.godserver.cn:11451/api/qq/region2?qq=" + userId ;
|
||||
Request request = new Request.Builder()
|
||||
.url(url)
|
||||
.build();
|
||||
Log.d("url",url);
|
||||
client.newCall(request).enqueue(new Callback() {
|
||||
@Override
|
||||
public void onFailure(Call call, IOException e) {
|
||||
e.printStackTrace();
|
||||
runOnUiThread(() -> Toast.makeText(LinkQQBot.this, "Request failed", Toast.LENGTH_SHORT).show());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResponse(Call call, Response response) throws IOException {
|
||||
if (response.isSuccessful()) {
|
||||
final String responseData = response.body().string();
|
||||
runOnUiThread(() -> {
|
||||
Log.d("TAG", "Response: " + responseData);
|
||||
Gson gson = new Gson();
|
||||
RegionData regionData = gson.fromJson(responseData, RegionData.class);
|
||||
sortUserRegions(regionData.getUserRegionList());
|
||||
});
|
||||
} else {
|
||||
runOnUiThread(() -> Toast.makeText(LinkQQBot.this, "Request not successful", Toast.LENGTH_SHORT).show());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void sortUserRegions(List<UserRegion> userRegions) {
|
||||
Collections.sort(userRegions, new Comparator<UserRegion>() {
|
||||
@Override
|
||||
public int compare(UserRegion o1, UserRegion o2) {
|
||||
return Integer.compare(o2.getPlayCount(), o1.getPlayCount());
|
||||
}
|
||||
});
|
||||
// 处理排序后的数据,例如显示在表格中
|
||||
displaySortedUserRegions(userRegions);
|
||||
}
|
||||
|
||||
private void displaySortedUserRegions(List<UserRegion> userRegions) {
|
||||
// 假设你有一个TableLayout来显示数据
|
||||
TableLayout tableLayout = findViewById(R.id.tableLayout);
|
||||
tableLayout.removeAllViews();
|
||||
|
||||
// 添加表头
|
||||
TableRow headerRow = new TableRow(this);
|
||||
TextView headerRegionId = new TextView(this);
|
||||
headerRegionId.setText("地区 ID");
|
||||
TextView headerPlayCount = new TextView(this);
|
||||
headerPlayCount.setText("PC次数");
|
||||
TextView headerProvince = new TextView(this);
|
||||
headerProvince.setText("省份");
|
||||
TextView headerCreated = new TextView(this);
|
||||
headerCreated.setText("版本初次日期");
|
||||
headerCreated.setTextColor(ContextCompat.getColor(LinkQQBot.context, R.color.primary));
|
||||
headerRegionId.setTextColor(ContextCompat.getColor(LinkQQBot.context, R.color.primary));
|
||||
headerPlayCount.setTextColor(ContextCompat.getColor(LinkQQBot.context, R.color.primary));
|
||||
headerProvince.setTextColor(ContextCompat.getColor(LinkQQBot.context, R.color.primary));
|
||||
headerRow.addView(headerRegionId);
|
||||
headerRow.addView(headerPlayCount);
|
||||
headerRow.addView(headerProvince);
|
||||
headerRow.addView(headerCreated);
|
||||
tableLayout.addView(headerRow);
|
||||
|
||||
// 添加数据行
|
||||
for (UserRegion userRegion : userRegions) {
|
||||
TableRow row = new TableRow(this);
|
||||
TextView textViewRegionId = new TextView(this);
|
||||
textViewRegionId.setTextColor(ContextCompat.getColor(LinkQQBot.context, R.color.primary));
|
||||
textViewRegionId.setText(String.valueOf(userRegion.getRegionId()));
|
||||
TextView textViewPlayCount = new TextView(this);
|
||||
textViewPlayCount.setTextColor(ContextCompat.getColor(LinkQQBot.context, R.color.primary));
|
||||
textViewPlayCount.setText(String.valueOf(userRegion.getPlayCount()));
|
||||
TextView textViewProvince = new TextView(this);
|
||||
textViewProvince.setTextColor(ContextCompat.getColor(LinkQQBot.context, R.color.primary));
|
||||
textViewProvince.setText(userRegion.getProvince());
|
||||
TextView textViewCreated = new TextView(this);
|
||||
textViewCreated.setText(userRegion.getCreated());
|
||||
textViewCreated.setTextColor(ContextCompat.getColor(LinkQQBot.context, R.color.primary));
|
||||
row.addView(textViewRegionId);
|
||||
row.addView(textViewPlayCount);
|
||||
row.addView(textViewProvince);
|
||||
row.addView(textViewCreated);
|
||||
tableLayout.addView(row);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ import com.bumptech.glide.request.RequestOptions;
|
||||
import com.google.android.material.button.MaterialButton;
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||
import com.google.android.material.snackbar.Snackbar;
|
||||
import com.google.android.material.textfield.TextInputEditText;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
@@ -41,9 +42,11 @@ import org.astral.findmaimaiultra.R;
|
||||
import org.astral.findmaimaiultra.adapter.MusicRatingAdapter;
|
||||
import org.astral.findmaimaiultra.adapter.SongAdapter;
|
||||
import org.astral.findmaimaiultra.adapter.SuggestMusicRatingAdapter;
|
||||
import org.astral.findmaimaiultra.been.ProjectSong;
|
||||
import org.astral.findmaimaiultra.been.faker.MaiUser;
|
||||
import org.astral.findmaimaiultra.been.faker.MusicRating;
|
||||
import org.astral.findmaimaiultra.been.faker.UserMusicList;
|
||||
import org.astral.findmaimaiultra.been.lx.Difficulty;
|
||||
import org.astral.findmaimaiultra.been.lx.Song;
|
||||
import org.astral.findmaimaiultra.databinding.FragmentMusicBinding;
|
||||
import org.astral.findmaimaiultra.ui.login.LinkQQBot;
|
||||
@@ -64,12 +67,14 @@ public class MusicFragment extends Fragment {
|
||||
private FragmentMusicBinding binding;
|
||||
private SharedPreferences setting;
|
||||
private SharedPreferences scorePrefs;
|
||||
private SharedPreferences project;
|
||||
private RecyclerView recyclerView;
|
||||
private MusicRatingAdapter adapter;
|
||||
private SuggestMusicRatingAdapter adapterSuggest;
|
||||
private DataAnalyzer dataAnalyzer;
|
||||
private List<UserMusicList> musicSongsRatings;
|
||||
private List<MusicRating> musicRatings = new ArrayList<>();
|
||||
private Map<Integer,List<MusicRating>> id2score= new HashMap<>();
|
||||
private String userId;
|
||||
private int iconId;
|
||||
private String username;
|
||||
@@ -81,6 +86,7 @@ public class MusicFragment extends Fragment {
|
||||
// 获取 SharedPreferences 实例
|
||||
setting = requireContext().getSharedPreferences("setting", Context.MODE_PRIVATE);
|
||||
scorePrefs = requireContext().getSharedPreferences("score", Context.MODE_PRIVATE);
|
||||
project = requireContext().getSharedPreferences("project",Context.MODE_PRIVATE);
|
||||
userId = setting.getString("userId", "未知");
|
||||
// 读取音乐评分列表
|
||||
musicSongsRatings = loadMusicRatings();
|
||||
@@ -91,6 +97,8 @@ public class MusicFragment extends Fragment {
|
||||
totalMusicRatings += musicRating.getRating();
|
||||
}
|
||||
}
|
||||
loadID2Score();
|
||||
|
||||
// 假设这里填充了音乐评分数据
|
||||
if (musicRatings.isEmpty()) {
|
||||
MusicRating empty = new MusicRating();
|
||||
@@ -103,6 +111,21 @@ public class MusicFragment extends Fragment {
|
||||
}
|
||||
}
|
||||
|
||||
private void loadID2Score() {
|
||||
ExecutorService executor = Executors.newSingleThreadExecutor();
|
||||
Handler handler = new Handler(Looper.getMainLooper());
|
||||
executor.execute(() -> {
|
||||
for (MusicRating m : musicRatings) {
|
||||
if (id2score.containsKey(m.getMusicId())) {
|
||||
Objects.requireNonNull(id2score.get(m.getMusicId())).add(m);
|
||||
}else{
|
||||
id2score.put(m.getMusicId(), new ArrayList<>());
|
||||
Objects.requireNonNull(id2score.get(m.getMusicId())).add(m);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void saveMusicRatings(List<UserMusicList> musicRatings) {
|
||||
Gson gson = new Gson();
|
||||
String json = gson.toJson(musicRatings);
|
||||
@@ -303,7 +326,9 @@ public class MusicFragment extends Fragment {
|
||||
startActivity(loginIntent);
|
||||
});
|
||||
}
|
||||
dataanlysis();
|
||||
if(musicRatings.size()>=50) {
|
||||
dataanlysis();
|
||||
}
|
||||
return root;
|
||||
}
|
||||
|
||||
@@ -322,7 +347,6 @@ public class MusicFragment extends Fragment {
|
||||
if (response.isSuccessful()) {
|
||||
String json = response.body().string();
|
||||
MaiUser maiUser = new Gson().fromJson(json, MaiUser.class);
|
||||
saveMusicRatings(maiUser.getUserMusicList());
|
||||
requireActivity().runOnUiThread(() -> {
|
||||
musicRatings.clear();
|
||||
for (UserMusicList musicSongsRating : maiUser.getUserMusicList()) {
|
||||
@@ -523,49 +547,135 @@ public class MusicFragment extends Fragment {
|
||||
builder.show();
|
||||
}
|
||||
|
||||
@SuppressLint({"SetTextI18n","MissingInflatedId"})
|
||||
|
||||
private void showSongDetailDialog(Song song) {
|
||||
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(requireContext(), R.style.CustomDialogStyle);
|
||||
View dialogView = LayoutInflater.from(requireContext()).inflate(R.layout.dialog_song_detail, null);
|
||||
builder.setView(dialogView);
|
||||
|
||||
// 设置歌曲详情
|
||||
ImageView songImage = dialogView.findViewById(R.id.backgroundLayout);
|
||||
Glide.with(this)
|
||||
.load("https://assets2.lxns.net/maimai/jacket/" + song.getId() + ".png")
|
||||
.into(songImage);
|
||||
TextView songTitle = dialogView.findViewById(R.id.song_title);
|
||||
songTitle.setTextColor(getResources().getColor(R.color.textcolorPrimary));
|
||||
TextView songArtist = dialogView.findViewById(R.id.song_artist);
|
||||
songArtist.setTextColor(getResources().getColor(R.color.textcolorPrimary));
|
||||
songTitle.setText(song.getTitle());
|
||||
songArtist.setText(song.getArtist());
|
||||
|
||||
// 初始化表格
|
||||
TableLayout tableLayout = dialogView.findViewById(R.id.song_table);
|
||||
for (int i = 0; i < 4; i++) { // 4 行
|
||||
Map<String, Difficulty[]> diffs = song.getDifficulties();
|
||||
//输出diffs
|
||||
int num = 0;
|
||||
List<Double> diff = new ArrayList<>();
|
||||
for (Map.Entry<String, Difficulty[]> entry : diffs.entrySet()) {
|
||||
String key = entry.getKey();
|
||||
Difficulty[] value = entry.getValue();
|
||||
for (Difficulty difficulty : value) {
|
||||
diff.add(difficulty.getLevel_value());
|
||||
num++;
|
||||
Log.d("TAG", "key: " + key + ", value: " + difficulty.getLevel());
|
||||
}
|
||||
}
|
||||
//diff倒置
|
||||
Collections.reverse(diff);
|
||||
for (int i = 0; i < num+1; i++) { // 4 行
|
||||
TableRow row = new TableRow(requireContext());
|
||||
for (int j = 0; j < 5; j++) { // 5 列
|
||||
TextView cell = new TextView(requireContext());
|
||||
cell.setText("数据 " + (i * 5 + j + 1)); // 示例数据
|
||||
cell.setPadding(8, 8, 8, 8);
|
||||
row.addView(cell);
|
||||
if (i ==0) {
|
||||
for (int j = 0; j < 9; j++) { // 5 列
|
||||
TextView cell = new TextView(requireContext());
|
||||
if (j==0) {
|
||||
cell.setText("完成度");
|
||||
cell.setTextColor(getResources().getColor(R.color.primary));
|
||||
}else {
|
||||
cell.setText(100.5001 - (((float)j-1) * 0.5) + "%");
|
||||
cell.setTextColor(getResources().getColor(R.color.textcolorPrimary));
|
||||
}
|
||||
cell.setPadding(8, 8, 8, 8);
|
||||
row.addView(cell);
|
||||
}
|
||||
}else {
|
||||
for (int j = 0; j < 9; j++) { // 5 列
|
||||
TextView cell = new TextView(requireContext());
|
||||
if (j==0) {
|
||||
cell.setText(diff.get(i-1).toString());
|
||||
cell.setTextColor(getResources().getColor(R.color.primary));
|
||||
}else {
|
||||
double a = 100.5001 - (((float)j-1) * 0.5);
|
||||
Log.d("TAG", "a: " + a);
|
||||
cell.setText("" + getRatingChart(diff.get(i-1),a)); // 示例数据
|
||||
cell.setTextColor(getResources().getColor(R.color.textcolorPrimary));
|
||||
|
||||
int finalI = i;
|
||||
int finalJ = j;
|
||||
if (j<3) {
|
||||
cell.setOnLongClickListener(v -> {
|
||||
//询问
|
||||
MaterialAlertDialogBuilder builder1 = new MaterialAlertDialogBuilder(requireContext(), R.style.CustomDialogStyle);
|
||||
builder1.setTitle("是否添加");
|
||||
builder1.setMessage("是否添加 : " + diff.get(finalI - 1) + " -> " + (100.5001 - (((float) finalJ - 1) * 0.5)) + "%");
|
||||
builder1.setPositiveButton("确定", (dialog, which) -> {
|
||||
// 添加到计划
|
||||
ProjectSong projectSong = new ProjectSong();
|
||||
projectSong.setId(song.getId());
|
||||
projectSong.setTargetLevel(diff.get(finalI - 1));
|
||||
projectSong.setTargetA(100.5001 - (((float) finalJ - 1) * 0.5));
|
||||
SharedPreferences.Editor projectE = project.edit();
|
||||
Gson gson = new Gson();
|
||||
String json = gson.toJson(projectSong);
|
||||
projectE.putString("project" + song.getId(), json);
|
||||
projectE.apply();
|
||||
dialog.dismiss();
|
||||
|
||||
Snackbar.make(v, "已添加", Snackbar.LENGTH_SHORT)
|
||||
.setAction("确定", null)
|
||||
.show();
|
||||
dataanlysis();
|
||||
});
|
||||
builder1.setNegativeButton("取消", (dialog, which) -> {
|
||||
dialog.dismiss();
|
||||
});
|
||||
builder1.show();
|
||||
return true;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
cell.setPadding(8, 8, 8, 8);
|
||||
row.addView(cell);
|
||||
}
|
||||
}
|
||||
tableLayout.addView(row);
|
||||
}
|
||||
|
||||
// 设置额外的 TextView
|
||||
TextView extraInfo = dialogView.findViewById(R.id.extra_info);
|
||||
extraInfo.setText("额外信息:这里可以显示更多内容");
|
||||
|
||||
// 设置按钮点击事件
|
||||
MaterialButton addToPlanButton = dialogView.findViewById(R.id.add_to_plan_button);
|
||||
addToPlanButton.setOnClickListener(v -> {
|
||||
// 将歌曲添加到计划中
|
||||
addToPlan(song);
|
||||
Toast.makeText(requireContext(), "已添加到计划", Toast.LENGTH_SHORT).show();
|
||||
});
|
||||
if (id2score.containsKey(song.getId()) || id2score.containsKey(song.getId() + 10000)) {
|
||||
List<MusicRating> m = id2score.get(song.getId());
|
||||
StringBuilder data = new StringBuilder("成绩\n");
|
||||
if (m == null) {
|
||||
m = (Objects.requireNonNull(id2score.get(song.getId() + 10000)));
|
||||
}else if (id2score.containsKey(song.getId() + 10000)){
|
||||
m.addAll(Objects.requireNonNull(id2score.get(song.getId() + 10000)));
|
||||
}
|
||||
for (MusicRating musicRating : m) {
|
||||
data.append(musicRating.getLevel_info()).append(" ").append((float)musicRating.getAchievement()/10000 + "%").append("\n");
|
||||
}
|
||||
extraInfo.setText("BPM" + song.getBpm() + "\n" + data);
|
||||
}
|
||||
else{
|
||||
extraInfo.setText("BPM" + song.getBpm());
|
||||
}
|
||||
extraInfo.setTextColor(getResources().getColor(R.color.textcolorPrimary));
|
||||
|
||||
builder.setPositiveButton("关闭", (dialog, which) -> dialog.dismiss());
|
||||
builder.show();
|
||||
}
|
||||
|
||||
private void addToPlan(Song song) {
|
||||
// 实现将歌曲添加到计划的逻辑
|
||||
}
|
||||
|
||||
private void sortMusicRatingsByRating() {
|
||||
Collections.sort(musicRatings, new Comparator<MusicRating>() {
|
||||
@@ -645,7 +755,12 @@ public class MusicFragment extends Fragment {
|
||||
Collections.sort(musicRatings, (o1, o2) -> Integer.compare(o2.getRating(), o1.getRating()));
|
||||
int total = 0;
|
||||
List<MusicRating> b50 = musicRatings.subList(0, 50);
|
||||
List<MusicRating> b100 = musicRatings.subList(50, 100);
|
||||
List<MusicRating> b100 = new ArrayList<>();
|
||||
if (musicRatings.size()<100) {
|
||||
b100 = musicRatings.subList(50, musicRatings.size());
|
||||
}else {
|
||||
b100 = musicRatings.subList(50, 100);
|
||||
}
|
||||
List<Integer> ids= new ArrayList<>();
|
||||
int worstRating = b50.get(b50.size() - 1).getRating();
|
||||
int bestRating = b50.get(0).getRating();
|
||||
@@ -767,6 +882,30 @@ public class MusicFragment extends Fragment {
|
||||
}
|
||||
}
|
||||
|
||||
//遍历project
|
||||
for (Map.Entry<String, ?> entry : project.getAll().entrySet()) {
|
||||
String key = entry.getKey();
|
||||
if (key.startsWith("project")) {
|
||||
String json = project.getString(key, null);
|
||||
if (json != null) {
|
||||
ProjectSong projectSong = new Gson().fromJson(json, ProjectSong.class);
|
||||
if (projectSong != null) {
|
||||
// 处理 projectSong 对象
|
||||
Song s = songs.get(projectSong.getId());
|
||||
MusicRating m = new MusicRating();
|
||||
m.setAchievement(0);
|
||||
m.setExtNum1((int)(projectSong.getTargetA()*10000));
|
||||
m.setExtNum2(getRatingChart(projectSong.getTargetLevel(), projectSong.getTargetA()));
|
||||
m.setMusicId(s.getId());
|
||||
m.setLevel_info(projectSong.getTargetLevel());
|
||||
m.setLevel((int) projectSong.getTargetLevel());
|
||||
m.setMusicName(s.getTitle());
|
||||
suggestMusicRatingList.add(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Update UI on the main thread
|
||||
int finalTotal = total;
|
||||
@@ -776,13 +915,17 @@ public class MusicFragment extends Fragment {
|
||||
|
||||
au.setText("Rating分析:最低分 " + worstRating + "分,最高分 " + bestRating + ",平均分" + (finalTotal / 50) + "分");
|
||||
|
||||
adapterSuggest = new SuggestMusicRatingAdapter(suggestMusicRatingList);
|
||||
adapterSuggest = new SuggestMusicRatingAdapter(suggestMusicRatingList,project);
|
||||
suggest.setAdapter(adapterSuggest);
|
||||
adapterSuggest.notifyDataSetChanged();
|
||||
});
|
||||
});
|
||||
}
|
||||
public int getRatingChart(double a1, double b1) {
|
||||
if(b1>970001) {
|
||||
b1 = b1 / 1000;
|
||||
}
|
||||
|
||||
double sys = 22.4;
|
||||
if (b1 >= 100.5000) {
|
||||
return (int) (a1 * 22.512);
|
||||
|
||||
@@ -2,9 +2,11 @@ package org.astral.findmaimaiultra.ui.slideshow;
|
||||
|
||||
import android.Manifest;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.UiModeManager;
|
||||
import android.content.*;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.res.Configuration;
|
||||
import android.os.Bundle;
|
||||
import android.provider.Settings;
|
||||
import android.util.Log;
|
||||
@@ -14,9 +16,11 @@ import android.view.ViewGroup;
|
||||
import android.webkit.WebView;
|
||||
import android.webkit.WebViewClient;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.cardview.widget.CardView;
|
||||
import androidx.core.app.ActivityCompat;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.fragment.app.Fragment;
|
||||
@@ -24,8 +28,11 @@ import androidx.lifecycle.ViewModelProvider;
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.google.android.material.button.MaterialButton;
|
||||
import com.google.android.material.radiobutton.MaterialRadioButton;
|
||||
import com.google.android.material.snackbar.Snackbar;
|
||||
import com.google.android.material.switchmaterial.SwitchMaterial;
|
||||
import com.google.android.material.textfield.TextInputEditText;
|
||||
|
||||
import org.astral.findmaimaiultra.R;
|
||||
import org.astral.findmaimaiultra.been.Release;
|
||||
import org.astral.findmaimaiultra.databinding.FragmentSlideshowBinding;
|
||||
import org.astral.findmaimaiultra.service.GitHubApiService;
|
||||
@@ -54,7 +61,7 @@ public class SlideshowFragment extends Fragment {
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE,
|
||||
Manifest.permission.WRITE_EXTERNAL_STORAGE
|
||||
};
|
||||
|
||||
private String theme;
|
||||
@Override
|
||||
public void onAttach(@NonNull Context context) {
|
||||
super.onAttach(context);
|
||||
@@ -76,6 +83,7 @@ public class SlideshowFragment extends Fragment {
|
||||
} else {
|
||||
requestPermissions();
|
||||
}
|
||||
theme = settingProperties.getString("selected_theme", "Theme.FindMaimaiUltra");
|
||||
}
|
||||
|
||||
private void show(String text) {
|
||||
@@ -101,6 +109,7 @@ public class SlideshowFragment extends Fragment {
|
||||
);
|
||||
}
|
||||
|
||||
@SuppressLint("ResourceAsColor")
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater,
|
||||
ViewGroup container, Bundle savedInstanceState) {
|
||||
@@ -178,9 +187,88 @@ public class SlideshowFragment extends Fragment {
|
||||
.into(user_avatar);
|
||||
TextView user_name = binding.username;
|
||||
user_name.setText(username);
|
||||
|
||||
themeClick(root);
|
||||
|
||||
|
||||
if (theme.contains("Pink")) {
|
||||
// 全部设置颜色
|
||||
user_name.setTextColor(ContextCompat.getColor(requireContext(), R.color.colorPrimary));
|
||||
binding.desc.setTextColor(ContextCompat.getColor(requireContext(), R.color.colorPrimary));
|
||||
binding.vits.setTextColor(ContextCompat.getColor(requireContext(), R.color.colorPrimary));
|
||||
binding.themeText.setTextColor(ContextCompat.getColor(requireContext(), R.color.colorPrimary));
|
||||
} else if (theme.contains("Blue")) {
|
||||
user_name.setTextColor(ContextCompat.getColor(requireContext(), R.color.textcolorPrimary2));
|
||||
binding.desc.setTextColor(ContextCompat.getColor(requireContext(), R.color.textcolorPrimary2));
|
||||
binding.vits.setTextColor(ContextCompat.getColor(requireContext(), R.color.textcolorPrimary2));
|
||||
binding.themeText.setTextColor(ContextCompat.getColor(requireContext(), R.color.textcolorPrimary2));
|
||||
} else if (theme.contains("Green")) {
|
||||
user_name.setTextColor(ContextCompat.getColor(requireContext(), R.color.lineBaseGreen));
|
||||
binding.desc.setTextColor(ContextCompat.getColor(requireContext(), R.color.lineBaseGreen));
|
||||
binding.vits.setTextColor(ContextCompat.getColor(requireContext(), R.color.lineBaseGreen));
|
||||
binding.themeText.setTextColor(ContextCompat.getColor(requireContext(), R.color.lineBaseGreen));
|
||||
}else if (theme.contains("White")) {
|
||||
user_name.setTextColor(ContextCompat.getColor(requireContext(), R.color.white));
|
||||
binding.desc.setTextColor(ContextCompat.getColor(requireContext(), R.color.white));
|
||||
binding.vits.setTextColor(ContextCompat.getColor(requireContext(), R.color.white));
|
||||
binding.themeText.setTextColor(ContextCompat.getColor(requireContext(), R.color.white));
|
||||
}else if (theme.contains("Gray")) {
|
||||
user_name.setTextColor(ContextCompat.getColor(requireContext(), R.color.black));
|
||||
binding.desc.setTextColor(ContextCompat.getColor(requireContext(), R.color.black));
|
||||
binding.vits.setTextColor(ContextCompat.getColor(requireContext(), R.color.black));
|
||||
binding.themeText.setTextColor(ContextCompat.getColor(requireContext(), R.color.black));
|
||||
}
|
||||
int nightModeFlags = getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
|
||||
boolean isNightMode = nightModeFlags == Configuration.UI_MODE_NIGHT_YES;
|
||||
if (isNightMode) {
|
||||
binding.scrollView.setBackgroundColor(getResources().getColor(R.color.primary_back2));
|
||||
binding.fraName.setBackgroundColor(getResources().getColor(R.color.primary_back2));
|
||||
}
|
||||
binding.view2.setBackgroundColor(R.color.black);
|
||||
binding.view3.setBackgroundColor(R.color.black);
|
||||
return root;
|
||||
}
|
||||
|
||||
|
||||
public boolean isDarkMode(Context context) {
|
||||
UiModeManager uiModeManager = (UiModeManager) context.getSystemService(Context.UI_MODE_SERVICE);
|
||||
return uiModeManager.getNightMode() == UiModeManager.MODE_NIGHT_YES;
|
||||
}
|
||||
private void themeClick(View root) {
|
||||
CardView cardPink = root.findViewById(R.id.cardPink);
|
||||
CardView cardGreen = root.findViewById(R.id.cardGreen);
|
||||
CardView cardBlue = root.findViewById(R.id.cardBlue);
|
||||
CardView cardWhite = root.findViewById(R.id.cardWhite);
|
||||
CardView cardGray = root.findViewById(R.id.cardGray);
|
||||
|
||||
View.OnClickListener themeClickListener = v -> {
|
||||
String selectedTheme = "Theme.FindMaimaiUltra";
|
||||
int id = v.getId();
|
||||
if (id == R.id.cardPink) {
|
||||
selectedTheme = "Theme.FindMaimaiUltra.Pink";
|
||||
} else if (id == R.id.cardGreen) {
|
||||
selectedTheme = "Theme.FindMaimaiUltra.Green";
|
||||
} else if (id == R.id.cardBlue) {
|
||||
selectedTheme = "Theme.FindMaimaiUltra.Blue";
|
||||
} else if (id == R.id.cardWhite) {
|
||||
selectedTheme = "Theme.FindMaimaiUltra.White";
|
||||
} else if (id == R.id.cardGray) {
|
||||
selectedTheme = "Theme.FindMaimaiUltra.Gray";
|
||||
}
|
||||
SharedPreferences.Editor editor = settingProperties.edit();
|
||||
editor.putString("selected_theme", selectedTheme);
|
||||
editor.apply();
|
||||
Snackbar .make(binding.getRoot(), "文本主题已更改", Snackbar.LENGTH_SHORT).show();
|
||||
|
||||
};
|
||||
|
||||
cardPink.setOnClickListener(themeClickListener);
|
||||
cardGreen.setOnClickListener(themeClickListener);
|
||||
cardBlue.setOnClickListener(themeClickListener);
|
||||
cardWhite.setOnClickListener(themeClickListener);
|
||||
cardGray.setOnClickListener(themeClickListener);
|
||||
}
|
||||
|
||||
private String getAppVersionName() {
|
||||
try {
|
||||
PackageInfo packageInfo = getContext().getPackageManager().getPackageInfo(getContext().getPackageName(), 0);
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 543 KiB |
@@ -14,15 +14,13 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="16dp"
|
||||
android:id="@+id/userBox"
|
||||
android:visibility="gone"
|
||||
android:paddingBottom="16dp">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/userId"
|
||||
android:id="@+id/key"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="qqbot"
|
||||
android:hint="Union绑定uuid"
|
||||
android:focusable="false"
|
||||
android:focusableInTouchMode="false"
|
||||
android:clickable="false"
|
||||
@@ -31,45 +29,21 @@
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="16dp"
|
||||
android:paddingBottom="16dp">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/key"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="用户邮箱"/>
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="16dp"
|
||||
android:paddingBottom="16dp">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/safecode"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="2fa应用内的6位数字代码(注册不用填)"/>
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<com.google.android.material.button.MaterialButton android:layout_width="match_parent"
|
||||
android:text="登录/注册 账号"
|
||||
android:text="绑定"
|
||||
android:textColor="@android:color/white"
|
||||
|
||||
android:id="@+id/bangding"
|
||||
android:layout_height="wrap_content">
|
||||
</com.google.android.material.button.MaterialButton>
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/getTicket"
|
||||
android:id="@+id/test"
|
||||
android:textColor="@android:color/white"
|
||||
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="拿 6 倍卷(公众号先发码)"/>
|
||||
android:text="ping"/>
|
||||
|
||||
<TableLayout
|
||||
android:id="@+id/tableLayout"
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:id="@+id/appBarLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_height="13mm"
|
||||
android:background="@color/colorPrimary"
|
||||
android:theme="@style/ThemeOverlay.MaterialComponents.Dark.ActionBar"
|
||||
tools:ignore="MissingConstraints">
|
||||
@@ -16,7 +16,7 @@
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="7mm"
|
||||
android:layout_height="11mm"
|
||||
android:tooltipText="FindMaimai"
|
||||
android:background="@color/colorPrimary"
|
||||
android:theme="@style/ThemeOverlay.MaterialComponents.Dark.ActionBar"
|
||||
|
||||
18
app/src/main/res/layout/dialog_map.xml
Normal file
18
app/src/main/res/layout/dialog_map.xml
Normal file
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.baidu.mapapi.map.MapView
|
||||
android:id="@+id/mapView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/confirmButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="确认位置" />
|
||||
</LinearLayout>
|
||||
@@ -1,37 +1,69 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<!-- 歌曲标题和作者 -->
|
||||
<TextView
|
||||
android:id="@+id/song_title"
|
||||
<!-- 图片和文本部分 -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="歌曲标题"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold" />
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical"
|
||||
android:layout_marginBottom="16dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/song_artist"
|
||||
<ImageView
|
||||
android:id="@+id/backgroundLayout"
|
||||
android:layout_width="140dp"
|
||||
android:layout_height="140dp"
|
||||
android:scaleType="centerCrop"
|
||||
android:layout_marginEnd="16dp" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/song_title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="歌曲标题"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/song_artist"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="歌曲作者"
|
||||
android:textSize="16sp" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<!-- 可左右滑动的表格 -->
|
||||
<HorizontalScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="歌曲作者"
|
||||
android:textSize="16sp"
|
||||
android:layout_marginBottom="16dp" />
|
||||
android:scrollbars="horizontal">
|
||||
<ScrollView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fillViewport="true">
|
||||
<TableLayout
|
||||
android:id="@+id/song_table"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:stretchColumns="*" />
|
||||
</ScrollView>
|
||||
|
||||
<!-- 表格 -->
|
||||
<TableLayout
|
||||
android:id="@+id/song_table"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:stretchColumns="*" />
|
||||
</HorizontalScrollView>
|
||||
|
||||
<!-- 额外信息 -->
|
||||
<TextView
|
||||
@@ -41,12 +73,5 @@
|
||||
android:text="额外信息"
|
||||
android:layout_marginTop="16dp" />
|
||||
|
||||
<!-- 添加到计划按钮 -->
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/add_to_plan_button"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="添加到计划"
|
||||
android:layout_marginTop="16dp" />
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
@@ -38,6 +38,7 @@
|
||||
<FrameLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
android:id="@+id/fraName"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/white"
|
||||
>
|
||||
@@ -56,6 +57,7 @@
|
||||
|
||||
<com.google.android.material.switchmaterial.SwitchMaterial
|
||||
android:id="@+id/switchBeta1"
|
||||
android:visibility="gone"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="@color/textcolorPrimary"
|
||||
@@ -101,10 +103,13 @@
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:background="?android:attr/dividerVertical"
|
||||
android:id="@+id/view2"
|
||||
android:background="?android:attr/dividerVertical"
|
||||
android:layout_marginTop="16dp"/>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:visibility="gone"
|
||||
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="16dp"
|
||||
@@ -122,6 +127,8 @@
|
||||
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:visibility="gone"
|
||||
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="16dp"
|
||||
@@ -136,6 +143,8 @@
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:visibility="gone"
|
||||
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="16dp"
|
||||
@@ -169,7 +178,68 @@
|
||||
android:backgroundTint="?attr/colorPrimary"
|
||||
android:paddingTop="16dp"
|
||||
android:paddingBottom="16dp"/>
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="@color/textcolorPrimary"
|
||||
android:textSize="18sp"
|
||||
android:id="@+id/themeText"
|
||||
android:text="文字主题"/>
|
||||
<HorizontalScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:scrollbars="none">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/themeCardContainer"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:padding="8dp">
|
||||
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/cardPink"
|
||||
android:layout_width="60dp"
|
||||
android:layout_height="60dp"
|
||||
android:layout_margin="8dp"
|
||||
app:cardBackgroundColor="@color/primary"
|
||||
app:cardCornerRadius="8dp" />
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/cardGreen"
|
||||
android:layout_width="60dp"
|
||||
android:layout_height="60dp"
|
||||
android:layout_margin="8dp"
|
||||
app:cardBackgroundColor="@color/lineBaseGreen"
|
||||
app:cardCornerRadius="8dp" />
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/cardBlue"
|
||||
android:layout_width="60dp"
|
||||
android:layout_height="60dp"
|
||||
android:layout_margin="8dp"
|
||||
app:cardBackgroundColor="@color/colorPrimary2"
|
||||
app:cardCornerRadius="8dp" />
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/cardWhite"
|
||||
android:layout_width="60dp"
|
||||
android:layout_height="60dp"
|
||||
android:layout_margin="8dp"
|
||||
app:cardBackgroundColor="@color/white"
|
||||
app:cardCornerRadius="8dp" />
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/cardGray"
|
||||
android:layout_width="60dp"
|
||||
android:layout_height="60dp"
|
||||
android:layout_margin="8dp"
|
||||
app:cardBackgroundColor="@color/black"
|
||||
app:cardCornerRadius="8dp" />
|
||||
|
||||
</LinearLayout>
|
||||
</HorizontalScrollView>
|
||||
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal">
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/save_settings_button"
|
||||
@@ -182,7 +252,9 @@
|
||||
android:paddingBottom="16dp"/>
|
||||
|
||||
</LinearLayout>
|
||||
<TextView android:layout_width="wrap_content" android:textColor="@color/textcolorPrimary"
|
||||
<TextView android:layout_width="wrap_content"
|
||||
android:textColor="@color/textcolorPrimary"
|
||||
android:id="@+id/desc"
|
||||
android:layout_height="wrap_content" android:text="@string/settin_body"/>
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
@@ -192,11 +264,13 @@
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:id="@+id/view3"
|
||||
android:background="?android:attr/dividerVertical"
|
||||
android:layout_marginTop="16dp"/>
|
||||
<TextView android:layout_width="wrap_content" android:textColor="@color/textcolorPrimary"
|
||||
android:layout_height="wrap_content" android:textSize="16dp" android:id="@+id/vits" />
|
||||
<WebView android:layout_width="match_parent" android:layout_height="600dp" android:id="@+id/develop"
|
||||
android:visibility="gone"
|
||||
tools:ignore="WebViewLayout"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
11
app/src/main/res/layout/fragment_webview.xml
Normal file
11
app/src/main/res/layout/fragment_webview.xml
Normal file
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".ui.earth.EarthFragment">
|
||||
|
||||
<WebView android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/webView"/>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -10,6 +10,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Song Title"
|
||||
android:textColor="@color/textcolorPrimary"
|
||||
android:textSize="16sp"
|
||||
android:textStyle="bold"
|
||||
android:ellipsize="end"
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="16sp"
|
||||
android:textColor="@color/textcolorPrimary"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
|
||||
@@ -13,11 +13,14 @@
|
||||
<item
|
||||
android:id="@+id/nav_music"
|
||||
android:title="@string/menu_music"/>
|
||||
<item
|
||||
android:id="@+id/nav_pixiv"
|
||||
android:title="@string/menu_pixiv"/>
|
||||
<!-- <item-->
|
||||
<!-- android:id="@+id/nav_pixiv"-->
|
||||
<!-- android:title="@string/menu_pixiv"/>-->
|
||||
<item
|
||||
android:id="@+id/nav_slideshow"
|
||||
android:title="@string/menu_slideshow"/>
|
||||
<item
|
||||
android:id="@+id/nav_earth"
|
||||
android:title="@string/menu_earth"/>
|
||||
</group>
|
||||
</menu>
|
||||
@@ -21,14 +21,19 @@
|
||||
android:name="org.astral.findmaimaiultra.ui.music.MusicFragment"
|
||||
android:label="@string/menu_music"
|
||||
tools:layout="@layout/fragment_music"/>
|
||||
<fragment
|
||||
android:id="@+id/nav_pixiv"
|
||||
android:name="org.astral.findmaimaiultra.ui.pixiv.PixivFragment"
|
||||
android:label="@string/menu_pixiv"
|
||||
tools:layout="@layout/fragment_pixiv"/>
|
||||
<!-- <fragment-->
|
||||
<!-- android:id="@+id/nav_pixiv"-->
|
||||
<!-- android:name="org.astral.findmaimaiultra.ui.pixiv.PixivFragment"-->
|
||||
<!-- android:label="@string/menu_pixiv"-->
|
||||
<!-- tools:layout="@layout/fragment_pixiv"/>-->
|
||||
<fragment
|
||||
android:id="@+id/nav_slideshow"
|
||||
android:name="org.astral.findmaimaiultra.ui.slideshow.SlideshowFragment"
|
||||
android:label="@string/menu_slideshow"
|
||||
tools:layout="@layout/fragment_slideshow"/>
|
||||
<fragment
|
||||
android:id="@+id/nav_earth"
|
||||
android:name="org.astral.findmaimaiultra.ui.earth.EarthFragment"
|
||||
android:label="@string/menu_earth"
|
||||
tools:layout="@layout/fragment_webview"/>
|
||||
</navigation>
|
||||
@@ -14,6 +14,8 @@
|
||||
<color name="primary_light">#D1C4E9</color>
|
||||
<color name="accent">#D5C4ED</color>
|
||||
<color name="primary_text">#8C8181</color>
|
||||
<color name="primary_back2">#323232</color>
|
||||
|
||||
<color name="backg">#CCA4A4</color>
|
||||
|
||||
<color name="secondary_text">#727272</color>
|
||||
@@ -28,6 +30,10 @@
|
||||
<color name="lineBaseGreen">#1DF687</color>
|
||||
<color name="VlineBaseGreen">#C2F6C4</color>
|
||||
<color name="textcolorPrimary">#D5C4ED</color>
|
||||
|
||||
<color name="textcolorPrimary2">#2196F3</color>
|
||||
<color name="colorPrimary2">#2196F3</color>
|
||||
|
||||
<color name="border_color">#000000</color> <!-- 黑色 -->
|
||||
<color name="menu_background_color">#FFFFFF</color> <!-- 白色背景 -->
|
||||
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
<string name="nav_header_subtitle">Reisa</string>
|
||||
<string name="action_settings">设置</string>
|
||||
<string name="menu_pixiv">Engine</string>
|
||||
<string name="menu_earth">全球地图</string>
|
||||
|
||||
|
||||
</resources>
|
||||
@@ -15,6 +15,50 @@
|
||||
<item name="popupMenuStyle">@style/MenuBackgroundStyle</item>
|
||||
|
||||
</style>
|
||||
|
||||
<style name="Theme.FindMaimaiUltra.Pink" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
|
||||
<item name="colorPrimary">@color/purple_500</item>
|
||||
<item name="colorPrimaryVariant">@color/purple_700</item>
|
||||
<item name="colorOnPrimary">@color/white</item>
|
||||
<item name="colorSecondary">@color/teal_200</item>
|
||||
<item name="colorOnSecondary">@color/black</item>
|
||||
</style>
|
||||
|
||||
<!-- Green Theme -->
|
||||
<style name="Theme.FindMaimaiUltra.Green" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
|
||||
<item name="colorPrimary">@color/lineBaseGreen</item>
|
||||
<item name="colorOnPrimary">@color/white</item>
|
||||
<item name="colorSecondary">@color/teal_200</item>
|
||||
<item name="colorOnSecondary">@color/black</item>
|
||||
</style>
|
||||
|
||||
|
||||
<!-- Blue Theme -->
|
||||
<style name="Theme.FindMaimaiUltra.Blue" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
|
||||
<item name="colorPrimary">@color/colorPrimary2</item>
|
||||
<item name="colorPrimaryVariant">@color/teal_700</item>
|
||||
<item name="colorOnPrimary">@color/white</item>
|
||||
<item name="colorSecondary">@color/teal_200</item>
|
||||
<item name="colorOnSecondary">@color/black</item>
|
||||
</style>
|
||||
|
||||
<!-- White Theme -->
|
||||
<style name="Theme.FindMaimaiUltra.White" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
|
||||
<item name="colorPrimary">@color/white</item>
|
||||
<item name="colorPrimaryVariant">@color/white</item>
|
||||
<item name="colorOnPrimary">@color/black</item>
|
||||
<item name="colorSecondary">@color/white</item>
|
||||
<item name="colorOnSecondary">@color/black</item>
|
||||
</style>
|
||||
|
||||
<!-- Gray Theme -->
|
||||
<style name="Theme.FindMaimaiUltra.Gray" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
|
||||
<item name="colorPrimary">@color/dividerColor</item>
|
||||
<item name="colorPrimaryVariant">@color/dividerColor</item>
|
||||
<item name="colorOnPrimary">@color/white</item>
|
||||
<item name="colorSecondary">@color/dividerColor</item>
|
||||
<item name="colorOnSecondary">@color/black</item>
|
||||
</style>
|
||||
<style name="Theme.FindMaimaiUltra.NoActionBar">
|
||||
<item name="windowActionBar">false</item>
|
||||
<item name="windowNoTitle">true</item>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
plugins {
|
||||
id 'com.android.application' version '8.0.0' apply false
|
||||
id 'com.android.application' version '8.8.0' apply false
|
||||
}
|
||||
|
||||
@@ -18,4 +18,4 @@ android.useAndroidX=true
|
||||
# Enables namespacing of each library's R class so that its R class includes only the
|
||||
# resources declared in the library itself and none from the library's dependencies,
|
||||
# thereby reducing the size of the R class for that library
|
||||
android.nonTransitiveRClass=true
|
||||
android.nonTransitiveRClass=true
|
||||
|
||||
Reference in New Issue
Block a user