排卡部分修复

This commit is contained in:
2025-04-20 02:54:12 +08:00
parent b5fb065208
commit 8a6e7d6dd9
13 changed files with 420 additions and 183 deletions

View File

@@ -11,7 +11,7 @@ android {
minSdk 29
targetSdk 34
versionCode 1
versionName "1.6.2"
versionName "1.6.3 beta"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
@@ -60,12 +60,10 @@ dependencies {
implementation 'com.baidu.lbsyun:BaiduMapSDK_Map:7.6.3'
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.1'
implementation 'com.journeyapps:zxing-android-embedded:4.3.0'
implementation 'com.github.yalantis:ucrop:2.2.8'
implementation 'com.github.chrisbanes:PhotoView:2.3.0'
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'com.google.android.material:material:1.8.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'androidx.navigation:navigation-fragment:2.5.3'
implementation 'androidx.navigation:navigation-ui:2.5.3'
@@ -73,6 +71,4 @@ dependencies {
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
implementation 'jp.wasabeef:glide-transformations:4.3.0'
}

View File

@@ -100,13 +100,6 @@
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
<data
android:scheme="org.astral.findmaimaiultra"
android:host="data" />
</intent-filter>
<intent-filter>
<action android:name="android.nfc.action.TAG_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
@@ -116,7 +109,9 @@
android:name="android.nfc.action.TECH_DISCOVERED"
android:resource="@xml/nfc_filter" />
</activity>
<activity
android:name=".ui.PortraitCaptureActivity"
android:screenOrientation="portrait" />
<activity
android:name=".ui.PageActivity"
android:exported="true"
@@ -129,11 +124,18 @@
android:label="@string/app_name"
android:theme="@style/Theme.FindMaimaiUltra.NoActionBar">
</activity>
<activity
android:name=".ui.PaikaActivity"
android:exported="true"
android:screenOrientation="portrait"
android:label="@string/app_name"
android:theme="@style/Theme.FindMaimaiUltra.NoActionBar">
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="org.astral.findmaimaiultra" />
</intent-filter>
</activity>
<activity
android:name=".ui.UpdateActivity"

View File

@@ -1,15 +1,21 @@
package org.astral.findmaimaiultra.ui;
import android.annotation.SuppressLint;
import android.app.PendingIntent;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.nfc.NdefMessage;
import android.nfc.NdefRecord;
import android.nfc.NfcAdapter;
import android.os.Handler;
import android.os.Parcelable;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.*;
import androidx.activity.result.ActivityResultLauncher;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
@@ -23,18 +29,23 @@ 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;
import com.journeyapps.barcodescanner.CaptureActivity;
import com.journeyapps.barcodescanner.ScanContract;
import com.journeyapps.barcodescanner.ScanOptions;
import okhttp3.*;
import org.astral.findmaimaiultra.R;
import org.jetbrains.annotations.NotNull;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;
public class PaikaActivity extends AppCompatActivity {
private SharedPreferences sharedPreferences;
private String use_party;
private String use_party = "未加入";
private String use_name;
private int iconId;
private int iconResId = iconId;
@@ -47,11 +58,19 @@ public class PaikaActivity extends AppCompatActivity {
private TextView player1Name;
private TextView player2Name;
private boolean isPlaying = false;
private NfcAdapter nfcAdapter;
private PendingIntent pendingIntent;
private int isNfc = 0;
@SuppressLint("MissingInflatedId")
@Override
protected void onStart() {
super.onStart();
setContentView(R.layout.activity_paika);
nfcAdapter = NfcAdapter.getDefaultAdapter(this);
pendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), PendingIntent.FLAG_IMMUTABLE);
processNfcIntent(getIntent());
sharedPreferences = getSharedPreferences("setting", Context.MODE_PRIVATE);
handler.postDelayed(refreshTask, 3000);
@@ -79,12 +98,7 @@ public class PaikaActivity extends AppCompatActivity {
status = sharedPreferences.getInt("paikastatus", 0);
toolbar = findViewById(R.id.toolbar);
Intent intent = getIntent();
if (intent.getStringExtra("data") != null) {
String data = intent.getStringExtra("data");
Log.d("123456", data);
use_party = data.split("paika")[1];
if (isNfc == 1) {
Log.d("partySetting", use_party);
if (sharedPreferences.getString("use_party", "").equals(use_party)) {
@@ -107,6 +121,13 @@ public class PaikaActivity extends AppCompatActivity {
}
}else
if(!sharedPreferences.getString("use_party", "").equals("")) {
if (!Objects.equals(use_party, "未加入")) {
if (status == 0) {
toolbar.setTitle(use_party + " 房间 " + use_name);
}else {
toolbar.setTitle(use_party + " 房间 " + use_name + " 正在队列");
}
}else {
use_party = sharedPreferences.getString("use_party", "");
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
builder.setTitle("重新进入房间");
@@ -129,7 +150,8 @@ public class PaikaActivity extends AppCompatActivity {
});
builder.setNegativeButton("取消", null);
builder.show();
}else if (status == 0 && intent.getStringExtra("data") == null) {
}
}else if ((status == 0) && (isNfc ==0)) {
//询问加入房价
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
builder.setTitle("进入房间");
@@ -163,7 +185,62 @@ public class PaikaActivity extends AppCompatActivity {
}
});
}
@Override
protected void onResume() {
super.onResume();
if (nfcAdapter != null) {
nfcAdapter.enableForegroundDispatch(this, pendingIntent, null, null);
}
}
@Override
protected void onPause() {
super.onPause();
if (nfcAdapter != null) {
nfcAdapter.disableForegroundDispatch(this);
}
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
processNfcIntent(intent);
}
private void processNfcIntent(Intent intent) {
Log.d("Paika123456", "123456");
if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction())) {
// 获取 NDEF 消息
Parcelable[] rawMessages = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
if (rawMessages != null) {
Log.d("Paika123456", "123");
for (Parcelable rawMessage : rawMessages) {
NdefMessage message = (NdefMessage) rawMessage;
for (NdefRecord record : message.getRecords()) {
// 检查是否是 URI 类型的记录
if (record.getTnf() == NdefRecord.TNF_WELL_KNOWN) {
String uri = parseUriFromNdefRecord(record);
use_party = uri.split("paika")[1];
isNfc = 1;
}
}
}
}
}
}
private String parseUriFromNdefRecord(NdefRecord record) {
try {
byte[] payload = record.getPayload();
if (payload != null && payload.length > 0) {
// 跳过第一个字节 (URI 标识符码)
return new String(payload, 1, payload.length - 1, StandardCharsets.UTF_8);
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private void doUPlay() {
// 使用 MaterialAlertDialogBuilder 创建弹窗
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
@@ -199,9 +276,12 @@ public class PaikaActivity extends AppCompatActivity {
break;
}
}
if (num.get() == 2 || num.get() == 3) {
if (num.get() == 2) {
Log.d("UPlayDialog", "上机 clicked");
play();
} else if (num.get() == 3) {
play3();
}else if (num.get() == 1 || num.get() ==0) {
Snackbar.make(v, "正在上机!", Snackbar.LENGTH_SHORT)
.setAction("确定", null)
@@ -274,10 +354,16 @@ public class PaikaActivity extends AppCompatActivity {
editor.putString("use_party", "");
editor.commit();
remove();
unplay();
Intent intent = new Intent(PaikaActivity.this, MainActivity.class);
startActivity(intent);
});
MaterialButton qrscan = dialogView.findViewById(R.id.qrscan);
qrscan.setOnClickListener(v -> {
//扫描二维码,读取为use_party;
qrScan();
});
builder.setView(dialogView);
builder.show();
@@ -285,12 +371,50 @@ public class PaikaActivity extends AppCompatActivity {
private Runnable refreshTask = new Runnable() {
@Override
public void run() {
try {
if (!use_party.isEmpty()) {
getData(); // 调用刷新方法
}
handler.postDelayed(this, 3000); // 每隔 2 秒执行一次
}catch (Exception e) {
}
}
};
private final ActivityResultLauncher<ScanOptions> qrScanLauncher = registerForActivityResult(
new ScanContract(),
result -> {
if (result.getContents() != null) {
// 获取扫描结果并赋值给 use_party
use_party = result.getContents();
Log.d("QRScan", "Scanned use_party: " + use_party);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putString("use_party", use_party);
editor.commit();
// 更新 UI 或执行其他逻辑
toolbar.setTitle(use_party + " 房间 " + use_name);
getData(); // 刷新数据
} else {
Log.d("QRScan", "Scan cancelled");
Snackbar.make(findViewById(R.id.back), "扫描取消", Snackbar.LENGTH_SHORT)
.setAction("确定", null).show();
}
}
);
// 定义 qrScan 方法
private void qrScan() {
ScanOptions options = new ScanOptions();
options.setPrompt("将二维码放入框内扫描"); // 设置提示信息
options.setOrientationLocked(true); // 锁定屏幕方向为竖屏
options.setBeepEnabled(true); // 扫描成功时播放提示音
options.setCaptureActivity(PortraitCaptureActivity.class); // 使用自定义的 CaptureActivity
options.setTimeout(5000); // 设置超时时间
qrScanLauncher.launch(options); // 启动扫描
}
private void getData() {
Request request = new Request.Builder()
.url("http://mai.godserver.cn:11451/api/mai/v1/party?party=" + use_party)
@@ -315,6 +439,11 @@ public class PaikaActivity extends AppCompatActivity {
Log.d("123456", "getData");
}
private void join() {
if (players.contains(use_name + "()" + iconId)) {
Snackbar.make(findViewById(R.id.back), "您已经加入该房间", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
return;
}
Request request = new Request.Builder()
.url("http://mai.godserver.cn:11451/api/mai/v1/party?party=" + use_party + "&people=" + use_name + "()" + iconId)
.post(RequestBody.create("", MediaType.parse("application/json")))
@@ -378,11 +507,25 @@ public class PaikaActivity extends AppCompatActivity {
}
});
}
private void play3() {
String changTo = players.get(2);
change(changTo,1);
}
private void unplay() {
remove();
status = 0;
use_party = "";
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putInt("paikastatus", status);
editor.putString("use_party", "");
editor.commit();
}
private void addDataToTableLayout() {
Context context = this;
if (players.isEmpty()) {
return;
}
handler.post(new Runnable() {
@Override
public void run() {
@@ -390,16 +533,27 @@ public class PaikaActivity extends AppCompatActivity {
//清空
tableLayout.removeAllViews();
try {
if (players.size() == 0) {
Glide.with(context)
.load("https://assets2.lxns.net/maimai/icon/0.png")
.into(player1Avatar);
player1Name.setText("等待玩家");
return;
}
if (players.size() == 1) {
Glide.with(context)
.load("https://assets2.lxns.net/maimai/icon/" + Integer.parseInt(players.get(0).split("\\(\\)")[1]) +".png")
.into(player1Avatar);
player1Name.setText(players.get(0).split("\\(\\)")[0]);
return;
}
Glide.with(context)
.load("https://assets2.lxns.net/maimai/icon/" + Integer.parseInt(players.get(0).split("\\(\\)")[1]) +".png")
.into(player1Avatar);
Glide.with(context)
.load("https://assets2.lxns.net/maimai/icon/" + Integer.parseInt(players.get(1).split("\\(\\)")[1]) +".png")
.into(player2Avatar);
}catch (Exception e) {
e.printStackTrace();
}
player1Name.setText(players.get(0).split("\\(\\)")[0]);
player2Name.setText(players.get(1).split("\\(\\)")[0]);
@@ -436,28 +590,7 @@ public class PaikaActivity extends AppCompatActivity {
fuzhushangji.setText("辅助上机");
change.setOnClickListener(v2->{
Request request = new Request.Builder()
.url("http://mai.godserver.cn:11451/api/mai/v1/party?party=" + use_party + "&people=" + use_name + "()" + iconResId + "&changeToPeople=" + players.get(finalI))
.put(RequestBody.create("", MediaType.parse("application/json")))
.build();
OkHttpClient client = new OkHttpClient();
Log.d("123456", "http://mai.godserver.cn:11451/api/mai/v1/party?party=" + use_party + "&people=" + use_name + "()" + iconResId + "&changeToPeople=" + players.get(finalI));
client.newCall(request).enqueue(new Callback() {
@Override
public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
if (response.isSuccessful()) {
getData();
Log.d("123456", "onResponse: " + response.body().string());
Snackbar.make(findViewById(R.id.back), "换位成功", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
}
}
@Override
public void onFailure(@NotNull Call call, @NotNull IOException e) {
}
});
change(players.get(finalI));
});
removeButton.setOnClickListener(v2->{
Request request = new Request.Builder()
@@ -524,9 +657,78 @@ public class PaikaActivity extends AppCompatActivity {
tableLayout.addView(separator);
}
}
}catch (Exception e) {
e.printStackTrace();
}
}
});
}
private void change(String to) {
Request request = new Request.Builder()
.url("http://mai.godserver.cn:11451/api/mai/v1/party?party=" + use_party + "&people=" + use_name + "()" + iconResId + "&changeToPeople=" + to)
.put(RequestBody.create("", MediaType.parse("application/json")))
.build();
OkHttpClient client = new OkHttpClient();
Log.d("123456", "http://mai.godserver.cn:11451/api/mai/v1/party?party=" + use_party + "&people=" + use_name + "()" + iconResId + "&changeToPeople=" + to);
client.newCall(request).enqueue(new Callback() {
@Override
public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
if (response.isSuccessful()) {
getData();
Log.d("123456", "onResponse: " + response.body().string());
Snackbar.make(findViewById(R.id.back), "换位成功", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
}
}
@Override
public void onFailure(@NotNull Call call, @NotNull IOException e) {
}
});
}
private void change(String to,int type) {
Request request = new Request.Builder()
.url("http://mai.godserver.cn:11451/api/mai/v1/party?party=" + use_party + "&people=" + use_name + "()" + iconResId + "&changeToPeople=" + to)
.put(RequestBody.create("", MediaType.parse("application/json")))
.build();
OkHttpClient client = new OkHttpClient();
Log.d("123456", "http://mai.godserver.cn:11451/api/mai/v1/party?party=" + use_party + "&people=" + use_name + "()" + iconResId + "&changeToPeople=" + to);
client.newCall(request).enqueue(new Callback() {
@Override
public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
if (response.isSuccessful()) {
Request request = new Request.Builder()
.url("http://mai.godserver.cn:11451/api/mai/v1/partyPlay?party=" + use_party )
.post(RequestBody.create("", MediaType.parse("application/json")))
.build();
OkHttpClient client = new OkHttpClient();
client.newCall(request).enqueue(new Callback() {
@Override
public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
Snackbar.make(findViewById(R.id.back), "上机成功!", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
getData();
}
@Override
public void onFailure(@NotNull Call call, @NotNull IOException e) {
}
});
}
}
@Override
public void onFailure(@NotNull Call call, @NotNull IOException e) {
}
});
}
// 用户类
private static class User {
private String name;

View File

@@ -0,0 +1,14 @@
package org.astral.findmaimaiultra.ui;
import android.content.pm.ActivityInfo;
import android.os.Bundle;
import com.journeyapps.barcodescanner.CaptureActivity;
public class PortraitCaptureActivity extends CaptureActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 强制设置为竖屏
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
}

View File

@@ -1,31 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="purple_200">#673AB7</color>
<color name="purple_500">#673AB7</color>
<color name="purple_700">#FF3700B3</color>
<color name="teal_200">#045D53</color>
<color name="night">#673AB7</color>
<color name="border_color">#FFFFFF</color> <!-- 白色 -->
<color name="teal_700">#FF018786</color>
<color name="black">#8A8282</color>
<color name="white">#FFFFFFFF</color>
<color name="primary">#673AB7</color>
<color name="primary_dark">#673AB7</color>
<color name="primary_light">#673AB7</color>
<color name="accent">#3F51B5</color>
<color name="primary_text">#212121</color>
<color name="secondary_text">#727272</color>
<color name="icons">#FFFFFF</color>
<color name="divider">#B6B6B6</color>
<color name="colorPrimary">#673AB7</color>
<color name="colorPrimaryVariant">#673AB7</color>
<color name="colorOnPrimary">#141313</color>
<color name="colorSecondary">#045D53</color>
<color name="colorSecondaryVariant">#018786</color>
<color name="colorOnSecondary">#000000</color>
<color name="lineBaseGreen">#045D53</color>
<color name="VlineBaseGreen">#C2F6C4</color>
<color name="textcolorPrimary">#FFFFFF</color>
<color name="red">#F44336</color>
</resources>

View File

@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="purple_200">#D5C4ED</color>
<color name="purple_500">#D5C4ED</color>
<color name="purple_700">#D5C4ED</color>
<color name="teal_200">#D5C4ED</color>
<color name="night">#D5C4ED</color>
<color name="teal_700">#D5C4ED</color>
<color name="black">#8A8282</color>
<color name="white">#FFFFFFFF</color>
<color name="primary">#D5C4ED</color>
<color name="primary_dark">#D5C4ED</color>
<color name="primary_light">#D1C4E9</color>
<color name="accent">#D5C4ED</color>
<color name="primary_text">#8C8181</color>
<color name="secondary_text">#727272</color>
<color name="icons">#FFFFFF</color>
<color name="divider">#B6B6B6</color>
<color name="colorPrimary">#D5C4ED</color>
<color name="colorPrimaryVariant">#D5C4ED</color>
<color name="colorOnPrimary">#FFFFFF</color>
<color name="colorSecondary">#D5C4ED</color>
<color name="colorSecondaryVariant">#D5C4ED</color>
<color name="colorOnSecondary">#000000</color>
<color name="lineBaseGreen">#1DF687</color>
<color name="VlineBaseGreen">#C2F6C4</color>
<color name="textcolorPrimary">#D5C4ED</color>
<color name="border_color">#000000</color> <!-- 黑色 -->
<color name="menu_background_color">#FFFFFF</color> <!-- 白色背景 -->
<color name="red">#F44336</color>
<color name="red2">#FF9189</color>
<color name="dividerColor">#7D7D7D</color>
</resources>

View File

@@ -47,4 +47,13 @@
android:textColor="@color/white"
app:backgroundTint="@color/colorPrimary"
tools:ignore="MissingConstraints"/>
<com.google.android.material.button.MaterialButton
android:id="@+id/qrscan"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:text="扫码加入排卡"
android:textColor="@color/white"
app:backgroundTint="@color/divider"
tools:ignore="MissingConstraints"/>
</LinearLayout>

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
xmlns:app="http://schemas.android.com/apk/res-auto"
android:theme="@style/Theme.FindMaimaiUltra">
<item android:id="@+id/action_settings"
android:title="@string/action_settings"
android:orderInCategory="100"
@@ -17,5 +17,4 @@
android:title="上传成绩"
android:orderInCategory="100"
app:showAsAction="never"/>
</menu>

View File

@@ -13,7 +13,7 @@
<color name="primary_dark">#D5C4ED</color>
<color name="primary_light">#D1C4E9</color>
<color name="accent">#D5C4ED</color>
<color name="primary_text">#212121</color>
<color name="primary_text">#8C8181</color>
<color name="secondary_text">#727272</color>
<color name="icons">#FFFFFF</color>
<color name="divider">#B6B6B6</color>
@@ -27,6 +27,7 @@
<color name="VlineBaseGreen">#C2F6C4</color>
<color name="textcolorPrimary">#D5C4ED</color>
<color name="border_color">#000000</color> <!-- 黑色 -->
<color name="menu_background_color">#FFFFFF</color> <!-- 白色背景 -->
<color name="red">#F44336</color>
<color name="red2">#FF9189</color>

View File

@@ -18,4 +18,7 @@
<style name="DialogAnimation"> <item name="android:windowEnterAnimation">@anim/dialog_enter</item>
<item name="android:windowExitAnimation">@anim/dialog_exit</item>
</style>
<style name="MenuBackgroundStyle">
<item name="android:background">@color/menu_background_color</item>
</style>
</resources>

View File

@@ -12,10 +12,14 @@
<!-- Status bar color. -->
<item name="android:statusBarColor">?attr/colorPrimaryVariant</item>
<!-- Customize your theme here. -->
<item name="popupMenuStyle">@style/MenuBackgroundStyle</item>
</style>
<style name="Theme.FindMaimaiUltra.NoActionBar">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
<item name="popupMenuStyle">@style/MenuBackgroundStyle</item>
</style>
<style name="Theme.FindMaimaiUltra.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar"/>
<style name="Theme.FindMaimaiUltra.PopupOverlay" parent="ThemeOverlay.AppCompat.Light"/>
@@ -31,6 +35,8 @@
<item name="colorOnSecondary">@color/black</item>
<!-- Status bar color. -->
<item name="android:statusBarColor">?attr/colorPrimaryVariant</item>
<item name="popupMenuStyle">@style/MenuBackgroundStyle</item>
<!-- Customize your theme here. -->
</style>
</resources>