推分推荐
This commit is contained in:
2
.idea/gradle.xml
generated
2
.idea/gradle.xml
generated
@@ -6,7 +6,6 @@
|
|||||||
<GradleProjectSettings>
|
<GradleProjectSettings>
|
||||||
<option name="testRunner" value="CHOOSE_PER_TEST" />
|
<option name="testRunner" value="CHOOSE_PER_TEST" />
|
||||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||||
<option name="gradleJvm" value="#GRADLE_LOCAL_JAVA_HOME" />
|
|
||||||
<option name="modules">
|
<option name="modules">
|
||||||
<set>
|
<set>
|
||||||
<option value="$PROJECT_DIR$" />
|
<option value="$PROJECT_DIR$" />
|
||||||
@@ -16,6 +15,5 @@
|
|||||||
<option name="resolveExternalAnnotations" value="false" />
|
<option name="resolveExternalAnnotations" value="false" />
|
||||||
</GradleProjectSettings>
|
</GradleProjectSettings>
|
||||||
</option>
|
</option>
|
||||||
<option name="parallelModelFetch" value="true" />
|
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
9
.idea/misc.xml
generated
9
.idea/misc.xml
generated
@@ -4,10 +4,17 @@
|
|||||||
<component name="FrameworkDetectionExcludesConfiguration">
|
<component name="FrameworkDetectionExcludesConfiguration">
|
||||||
<file type="web" url="file://$PROJECT_DIR$" />
|
<file type="web" url="file://$PROJECT_DIR$" />
|
||||||
</component>
|
</component>
|
||||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="jbr-21" project-jdk-type="JavaSDK">
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="17" project-jdk-type="JavaSDK">
|
||||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||||
</component>
|
</component>
|
||||||
<component name="ProjectType">
|
<component name="ProjectType">
|
||||||
<option name="id" value="Android" />
|
<option name="id" value="Android" />
|
||||||
</component>
|
</component>
|
||||||
|
<component name="VisualizationToolProject">
|
||||||
|
<option name="state">
|
||||||
|
<ProjectState>
|
||||||
|
<option name="scale" value="0.2727272727272727" />
|
||||||
|
</ProjectState>
|
||||||
|
</option>
|
||||||
|
</component>
|
||||||
</project>
|
</project>
|
||||||
@@ -11,7 +11,7 @@ android {
|
|||||||
minSdk 29
|
minSdk 29
|
||||||
targetSdk 34
|
targetSdk 34
|
||||||
versionCode 1
|
versionCode 1
|
||||||
versionName "1.6.3"
|
versionName "1.6.4 beta"
|
||||||
|
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -119,12 +119,17 @@
|
|||||||
android:theme="@style/Theme.FindMaimaiUltra.NoActionBar">
|
android:theme="@style/Theme.FindMaimaiUltra.NoActionBar">
|
||||||
</activity>
|
</activity>
|
||||||
<activity
|
<activity
|
||||||
android:name=".ui.LinkQQBot"
|
android:name=".ui.login.LinkQQBot"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:theme="@style/Theme.FindMaimaiUltra.NoActionBar">
|
android:theme="@style/Theme.FindMaimaiUltra.NoActionBar">
|
||||||
</activity>
|
</activity>
|
||||||
|
<activity android:name=".ui.WebsiteActivity"
|
||||||
|
android:exported="true"
|
||||||
|
android:screenOrientation="portrait"
|
||||||
|
android:label="@string/app_name"
|
||||||
|
android:theme="@style/Theme.FindMaimaiUltra.NoActionBar">
|
||||||
|
</activity>
|
||||||
<activity
|
<activity
|
||||||
android:name=".ui.PaikaActivity"
|
android:name=".ui.PaikaActivity"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
|
|||||||
1
app/src/main/assets/musicLike.json
Normal file
1
app/src/main/assets/musicLike.json
Normal file
File diff suppressed because one or more lines are too long
1
app/src/main/assets/songs_cache.json
Normal file
1
app/src/main/assets/songs_cache.json
Normal file
File diff suppressed because one or more lines are too long
@@ -0,0 +1,142 @@
|
|||||||
|
package org.astral.findmaimaiultra.adapter;
|
||||||
|
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
import android.widget.TextView;
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
import com.bumptech.glide.Glide;
|
||||||
|
import com.bumptech.glide.load.engine.DiskCacheStrategy;
|
||||||
|
import com.bumptech.glide.request.RequestOptions;
|
||||||
|
import com.bumptech.glide.signature.ObjectKey;
|
||||||
|
import jp.wasabeef.glide.transformations.BlurTransformation;
|
||||||
|
import org.astral.findmaimaiultra.R;
|
||||||
|
import org.astral.findmaimaiultra.been.faker.MusicRating;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class SuggestMusicRatingAdapter extends RecyclerView.Adapter<SuggestMusicRatingAdapter.ViewHolder> {
|
||||||
|
|
||||||
|
private List<MusicRating> musicRatings;
|
||||||
|
private OnItemClickListener listener;
|
||||||
|
|
||||||
|
public interface OnItemClickListener {
|
||||||
|
void onItemClick(MusicRating musicRating);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOnItemClickListener(OnItemClickListener listener) {
|
||||||
|
|
||||||
|
this.listener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SuggestMusicRatingAdapter(List<MusicRating> musicRatings) {
|
||||||
|
this.musicRatings = musicRatings;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||||
|
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_suggest_music_rating, parent, false);
|
||||||
|
return new ViewHolder(view);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
|
||||||
|
MusicRating musicRating = musicRatings.get(position);
|
||||||
|
holder.musicName.setText(musicRating.getMusicName());
|
||||||
|
holder.level.setText("Level " + musicRating.getLevel_info() + " " + musicRating.getExtNum2());
|
||||||
|
String ac = String.valueOf(musicRating.getAchievement());
|
||||||
|
String target = String.valueOf(musicRating.getExtNum1());
|
||||||
|
//从后往前第5位加.
|
||||||
|
if(ac.length()>4) {
|
||||||
|
ac = ac.substring(0, ac.length() - 4) + "." + ac.substring(ac.length() - 4);
|
||||||
|
}
|
||||||
|
if(target.length()>4) {
|
||||||
|
target = target.substring(0, target.length() - 4) + "." + target.substring(target.length() - 4);
|
||||||
|
}
|
||||||
|
holder.ach.setText(ac + " -> " + target);
|
||||||
|
int id = musicRating.getMusicId();
|
||||||
|
if (id > 10000) {
|
||||||
|
id = id - 10000;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 假设 musicRating 有一个方法 getCoverImageUrl() 返回图片的URL
|
||||||
|
String imageUrl = "https://assets2.lxns.net/maimai/jacket/" + id + ".png";
|
||||||
|
if (imageUrl != null) {
|
||||||
|
RequestOptions options = new RequestOptions()
|
||||||
|
.diskCacheStrategy(DiskCacheStrategy.ALL) // 使用所有缓存策略
|
||||||
|
.signature(new ObjectKey(musicRating.getMusicId())); // 使用 MusicId 作为签名
|
||||||
|
|
||||||
|
Glide.with(holder.itemView.getContext())
|
||||||
|
.load(imageUrl)
|
||||||
|
.apply(options)
|
||||||
|
.into(holder.backgroundLayout);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据 achievement 数据加载相应的图片
|
||||||
|
int achievement = musicRating.getExtNum1();
|
||||||
|
int achievementImageResId = getAchievementImageResId(achievement);
|
||||||
|
if (achievementImageResId != 0) {
|
||||||
|
Glide.with(holder.itemView.getContext())
|
||||||
|
.load(achievementImageResId)
|
||||||
|
.into(holder.achievementImage);
|
||||||
|
} else {
|
||||||
|
holder.achievementImage.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
holder.itemView.setOnClickListener(v -> {
|
||||||
|
if (listener != null) {
|
||||||
|
listener.onItemClick(musicRating);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getAchievementImageResId(int achievement) {
|
||||||
|
// 根据 achievement 值返回相应的图片资源 ID
|
||||||
|
// 例如:
|
||||||
|
if(achievement > 1005000) {
|
||||||
|
return R.drawable.rank_sssp;
|
||||||
|
} else if (achievement > 1000000) {
|
||||||
|
return R.drawable.rank_sss;
|
||||||
|
} else if (achievement > 995000) {
|
||||||
|
return R.drawable.rank_ssp;
|
||||||
|
} else if (achievement > 990000) {
|
||||||
|
return R.drawable.rank_ss;
|
||||||
|
} else if (achievement > 980000) {
|
||||||
|
return R.drawable.rank_sp;
|
||||||
|
} else if (achievement > 970000) {
|
||||||
|
return R.drawable.rank_s;
|
||||||
|
} else if (achievement > 940000) {
|
||||||
|
return R.drawable.rank_aaa;
|
||||||
|
} else if (achievement > 900000) {
|
||||||
|
return R.drawable.rank_aaa;
|
||||||
|
} else if (achievement > 800000) {
|
||||||
|
return R.drawable.rank_a;
|
||||||
|
}
|
||||||
|
return R.drawable.rank_bbb;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getItemCount() {
|
||||||
|
return musicRatings.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ViewHolder extends RecyclerView.ViewHolder {
|
||||||
|
TextView musicName;
|
||||||
|
TextView level;
|
||||||
|
TextView ach;
|
||||||
|
ImageView backgroundLayout;
|
||||||
|
ImageView achievementImage;
|
||||||
|
|
||||||
|
public ViewHolder(@NonNull View itemView) {
|
||||||
|
super(itemView);
|
||||||
|
musicName = itemView.findViewById(R.id.musicName);
|
||||||
|
level = itemView.findViewById(R.id.level);
|
||||||
|
ach = itemView.findViewById(R.id.ach);
|
||||||
|
backgroundLayout = itemView.findViewById(R.id.backgroundLayout);
|
||||||
|
achievementImage = itemView.findViewById(R.id.achievementImage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
package org.astral.findmaimaiultra.been.lx;
|
package org.astral.findmaimaiultra.been.lx;
|
||||||
|
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
public class Song {
|
public class Song {
|
||||||
@@ -11,6 +13,8 @@ public class Song {
|
|||||||
private int bpm;
|
private int bpm;
|
||||||
private int version;
|
private int version;
|
||||||
private String rights;
|
private String rights;
|
||||||
|
@SerializedName("difficulties")
|
||||||
|
|
||||||
private Map<String, Difficulty[]> difficulties;
|
private Map<String, Difficulty[]> difficulties;
|
||||||
|
|
||||||
// Getters and Setters
|
// Getters and Setters
|
||||||
|
|||||||
@@ -229,6 +229,7 @@ public class MainActivity extends AppCompatActivity implements ImagePickerListen
|
|||||||
updatePlace();
|
updatePlace();
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,67 @@
|
|||||||
|
package org.astral.findmaimaiultra.ui;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.webkit.WebSettings;
|
||||||
|
import android.webkit.WebView;
|
||||||
|
import android.webkit.WebViewClient;
|
||||||
|
|
||||||
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
|
|
||||||
|
import org.astral.findmaimaiultra.R;
|
||||||
|
|
||||||
|
public class WebsiteActivity extends AppCompatActivity {
|
||||||
|
|
||||||
|
private WebView webView;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
setContentView(R.layout.fullscreen_webview_dialog);
|
||||||
|
|
||||||
|
webView = findViewById(R.id.webView);
|
||||||
|
|
||||||
|
// 获取 SharedPreferences
|
||||||
|
SharedPreferences setting = getSharedPreferences("setting", MODE_PRIVATE);
|
||||||
|
String sessionId = setting.getString("sessionId", "");
|
||||||
|
|
||||||
|
// 启用 JavaScript
|
||||||
|
WebSettings webSettings = webView.getSettings();
|
||||||
|
webSettings.setJavaScriptEnabled(true);
|
||||||
|
|
||||||
|
// 设置 WebViewClient 在页面加载完成后注入 JS
|
||||||
|
webView.setWebViewClient(new WebViewClient() {
|
||||||
|
@Override
|
||||||
|
public void onPageFinished(WebView view, String url) {
|
||||||
|
super.onPageFinished(view, url);
|
||||||
|
|
||||||
|
// 注入 JavaScript 设置 localStorage.sessionId
|
||||||
|
String jsCode = "localStorage.setItem('sessionId', '" + sessionId + "');";
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||||
|
webView.evaluateJavascript(jsCode, null);
|
||||||
|
} else {
|
||||||
|
webView.loadUrl("javascript:" + jsCode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 从 Intent 获取要加载的 URL
|
||||||
|
String url = getIntent().getStringExtra("url");
|
||||||
|
if (url != null && !url.isEmpty()) {
|
||||||
|
webView.loadUrl(url);
|
||||||
|
} else {
|
||||||
|
finish(); // 如果没有 URL,直接关闭 Activity
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBackPressed() {
|
||||||
|
if (webView.canGoBack()) {
|
||||||
|
webView.goBack();
|
||||||
|
} else {
|
||||||
|
super.onBackPressed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,32 +1,43 @@
|
|||||||
// HackGetUserId.java
|
// HackGetUserId.java
|
||||||
package org.astral.findmaimaiultra.ui;
|
package org.astral.findmaimaiultra.ui.login;
|
||||||
|
|
||||||
import android.Manifest;
|
import android.Manifest;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.provider.MediaStore;
|
||||||
|
import android.util.Base64;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.TableLayout;
|
import android.widget.*;
|
||||||
import android.widget.TableRow;
|
|
||||||
import android.widget.TextView;
|
|
||||||
import android.widget.Toast;
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.appcompat.app.AlertDialog;
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
import androidx.core.app.ActivityCompat;
|
import androidx.core.app.ActivityCompat;
|
||||||
import androidx.core.content.ContextCompat;
|
import androidx.core.content.ContextCompat;
|
||||||
import com.google.android.material.button.MaterialButton;
|
import com.google.android.material.button.MaterialButton;
|
||||||
|
import com.google.android.material.snackbar.Snackbar;
|
||||||
import com.google.android.material.textfield.TextInputEditText;
|
import com.google.android.material.textfield.TextInputEditText;
|
||||||
import com.google.android.material.textfield.TextInputLayout;
|
import com.google.android.material.textfield.TextInputLayout;
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
|
import com.google.zxing.BarcodeFormat;
|
||||||
|
import com.google.zxing.MultiFormatWriter;
|
||||||
|
import com.google.zxing.WriterException;
|
||||||
|
import com.google.zxing.common.BitMatrix;
|
||||||
import okhttp3.*;
|
import okhttp3.*;
|
||||||
import org.astral.findmaimaiultra.R;
|
import org.astral.findmaimaiultra.R;
|
||||||
import org.astral.findmaimaiultra.been.faker.RegionData;
|
import org.astral.findmaimaiultra.been.faker.RegionData;
|
||||||
import org.astral.findmaimaiultra.been.faker.UserData;
|
import org.astral.findmaimaiultra.been.faker.UserData;
|
||||||
import org.astral.findmaimaiultra.been.faker.UserRegion;
|
import org.astral.findmaimaiultra.been.faker.UserRegion;
|
||||||
|
import org.astral.findmaimaiultra.ui.MainActivity;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -64,11 +75,7 @@ public class LinkQQBot extends AppCompatActivity {
|
|||||||
MaterialButton bangding = findViewById(R.id.bangding);
|
MaterialButton bangding = findViewById(R.id.bangding);
|
||||||
bangding.setOnClickListener(v -> {
|
bangding.setOnClickListener(v -> {
|
||||||
if (key.getText().toString().equals("")) {
|
if (key.getText().toString().equals("")) {
|
||||||
Toast.makeText(this, "请输入基于QQ机器人获取的Key", Toast.LENGTH_SHORT).show();
|
Toast.makeText(this, "请输入邮箱", Toast.LENGTH_SHORT).show();
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (safecode.getText().toString().equals("")) {
|
|
||||||
Toast.makeText(this, "请输入您的安全码", Toast.LENGTH_SHORT).show();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
@@ -124,11 +131,65 @@ public class LinkQQBot extends AppCompatActivity {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendApiRequest(String key,String safecode,int code) throws Exception {
|
private void getUserInfo() {
|
||||||
String url = "http://mai.godserver.cn:11451/api/qq/safeCoding?result=" + key + "&safecode=" + safecode;
|
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()
|
Request request = new Request.Builder()
|
||||||
.url(url)
|
.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();
|
||||||
|
try {
|
||||||
|
getUserRegionData(user.getQqId());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(@NotNull Call call, @NotNull IOException e) {
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
private void bindUser() {
|
||||||
|
|
||||||
|
}
|
||||||
|
private void sendApiRequest(String key,String safecode,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();
|
.build();
|
||||||
Log.d("TAG", "sendApiRequest: " + url);
|
Log.d("TAG", "sendApiRequest: " + url);
|
||||||
client.newCall(request).enqueue(new Callback() {
|
client.newCall(request).enqueue(new Callback() {
|
||||||
@@ -142,28 +203,44 @@ public class LinkQQBot extends AppCompatActivity {
|
|||||||
public void onResponse(Call call, Response response) throws IOException {
|
public void onResponse(Call call, Response response) throws IOException {
|
||||||
if (response.isSuccessful()) {
|
if (response.isSuccessful()) {
|
||||||
final String responseData = response.body().string();
|
final String responseData = response.body().string();
|
||||||
|
SharedPreferences sharedPreferences = getSharedPreferences("setting", Context.MODE_PRIVATE);
|
||||||
|
SharedPreferences.Editor editor = sharedPreferences.edit();
|
||||||
|
|
||||||
runOnUiThread(() -> {
|
runOnUiThread(() -> {
|
||||||
Toast.makeText(LinkQQBot.this, "Response: " + responseData, Toast.LENGTH_LONG).show();
|
Message message = new Gson().fromJson(responseData, Message.class);
|
||||||
Log.d("TAG", "Response: " + responseData);
|
if ("login".equals(message.getType())) {
|
||||||
if(responseData.equals("错误") && code==1) {
|
if (message.getCode() == 200) {
|
||||||
try {
|
// 登录成功
|
||||||
sendApiRequest(safecode,key,2);
|
editor.remove("sessionId");
|
||||||
} catch (Exception e) {
|
editor.putString("sessionId", message.getSessionId());
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
userId.setText(responseData);
|
|
||||||
SharedPreferences.Editor editor = sp.edit();
|
|
||||||
editor.putString("userId", responseData);
|
|
||||||
editor.apply();
|
editor.apply();
|
||||||
Toast.makeText(LinkQQBot.this, "设置已保存,您的UsrId已写入硬盘!", Toast.LENGTH_SHORT).show();
|
Log.d("TAG","成功!");
|
||||||
try {
|
Snackbar.make(LinkQQBot.this.findViewById(android.R.id.content), "登录成功!", Snackbar.LENGTH_LONG)
|
||||||
getUserRegionData(responseData);
|
.show();
|
||||||
getUserData(responseData);
|
} else {
|
||||||
} catch (Exception e) {
|
// 登录失败
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
}
|
||||||
|
} 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 {
|
} else {
|
||||||
runOnUiThread(() -> Toast.makeText(LinkQQBot.this, "Request not successful", Toast.LENGTH_SHORT).show());
|
runOnUiThread(() -> Toast.makeText(LinkQQBot.this, "Request not successful", Toast.LENGTH_SHORT).show());
|
||||||
@@ -171,6 +248,48 @@ public class LinkQQBot extends AppCompatActivity {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
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 {
|
private void getUserData(String userId) throws Exception {
|
||||||
String url = "http://mai.godserver.cn:11451/api/qq/userData?qq=" + userId ;
|
String url = "http://mai.godserver.cn:11451/api/qq/userData?qq=" + userId ;
|
||||||
|
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package org.astral.findmaimaiultra.ui.login;
|
||||||
|
|
||||||
|
public class LoginRequest {
|
||||||
|
private String email;
|
||||||
|
private String codeOrPassword;
|
||||||
|
|
||||||
|
public String getEmail() {
|
||||||
|
return email;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEmail(String email) {
|
||||||
|
this.email = email;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCodeOrPassword() {
|
||||||
|
return codeOrPassword;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCodeOrPassword(String codeOrPassword) {
|
||||||
|
this.codeOrPassword = codeOrPassword;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
package org.astral.findmaimaiultra.ui.login;
|
||||||
|
|
||||||
|
public class Message {
|
||||||
|
private String type;
|
||||||
|
private String content;
|
||||||
|
private String contentType;
|
||||||
|
private String sessionId;
|
||||||
|
private int code;
|
||||||
|
private long timestamp;
|
||||||
|
|
||||||
|
public String getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getContentType() {
|
||||||
|
return contentType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setContentType(String contentType) {
|
||||||
|
this.contentType = contentType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSessionId() {
|
||||||
|
return sessionId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSessionId(String sessionId) {
|
||||||
|
this.sessionId = sessionId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setType(String type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getContent() {
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setContent(String content) {
|
||||||
|
this.content = content;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCode() {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCode(int code) {
|
||||||
|
this.code = code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getTimestamp() {
|
||||||
|
return timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTimestamp(long timestamp) {
|
||||||
|
this.timestamp = timestamp;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
package org.astral.findmaimaiultra.ui.login;
|
||||||
|
|
||||||
|
public class User {
|
||||||
|
private String id;
|
||||||
|
private String name;
|
||||||
|
private String email;
|
||||||
|
private String twoFactor;
|
||||||
|
private String avatar;
|
||||||
|
private String lastLogin;
|
||||||
|
private String qqId;
|
||||||
|
private String mai_avatarId;
|
||||||
|
private String mai_userName;
|
||||||
|
|
||||||
|
public String getQqId() {
|
||||||
|
return qqId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setQqId(String qqId) {
|
||||||
|
this.qqId = qqId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMai_avatarId() {
|
||||||
|
return mai_avatarId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMai_avatarId(String mai_avatarId) {
|
||||||
|
this.mai_avatarId = mai_avatarId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMai_userName() {
|
||||||
|
return mai_userName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMai_userName(String mai_userName) {
|
||||||
|
this.mai_userName = mai_userName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(String id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getEmail() {
|
||||||
|
return email;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEmail(String email) {
|
||||||
|
this.email = email;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTwoFactor() {
|
||||||
|
return twoFactor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTwoFactor(String twoFactor) {
|
||||||
|
this.twoFactor = twoFactor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAvatar() {
|
||||||
|
return avatar;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAvatar(String avatar) {
|
||||||
|
this.avatar = avatar;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLastLogin() {
|
||||||
|
return lastLogin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLastLogin(String lastLogin) {
|
||||||
|
this.lastLogin = lastLogin;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,13 +1,19 @@
|
|||||||
package org.astral.findmaimaiultra.ui.music;
|
package org.astral.findmaimaiultra.ui.music;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.app.Dialog;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.graphics.BitmapFactory;
|
||||||
|
import android.graphics.Canvas;
|
||||||
|
import android.graphics.Paint;
|
||||||
|
import android.graphics.drawable.BitmapDrawable;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.LayoutInflater;
|
import android.os.Handler;
|
||||||
import android.view.View;
|
import android.os.Looper;
|
||||||
import android.view.ViewGroup;
|
import android.util.Log;
|
||||||
|
import android.view.*;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
@@ -19,6 +25,7 @@ import androidx.recyclerview.widget.GridLayoutManager;
|
|||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
import com.bumptech.glide.Glide;
|
import com.bumptech.glide.Glide;
|
||||||
import com.bumptech.glide.request.RequestOptions;
|
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.dialog.MaterialAlertDialogBuilder;
|
||||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
@@ -26,19 +33,25 @@ import com.google.gson.reflect.TypeToken;
|
|||||||
import okhttp3.*;
|
import okhttp3.*;
|
||||||
import org.astral.findmaimaiultra.R;
|
import org.astral.findmaimaiultra.R;
|
||||||
import org.astral.findmaimaiultra.adapter.MusicRatingAdapter;
|
import org.astral.findmaimaiultra.adapter.MusicRatingAdapter;
|
||||||
|
import org.astral.findmaimaiultra.adapter.SuggestMusicRatingAdapter;
|
||||||
import org.astral.findmaimaiultra.been.faker.MaiUser;
|
import org.astral.findmaimaiultra.been.faker.MaiUser;
|
||||||
import org.astral.findmaimaiultra.been.faker.MusicRating;
|
import org.astral.findmaimaiultra.been.faker.MusicRating;
|
||||||
import org.astral.findmaimaiultra.been.faker.UserMusicList;
|
import org.astral.findmaimaiultra.been.faker.UserMusicList;
|
||||||
|
import org.astral.findmaimaiultra.been.lx.Song;
|
||||||
import org.astral.findmaimaiultra.databinding.FragmentMusicBinding;
|
import org.astral.findmaimaiultra.databinding.FragmentMusicBinding;
|
||||||
|
import org.astral.findmaimaiultra.ui.login.LinkQQBot;
|
||||||
import org.astral.findmaimaiultra.ui.MainActivity;
|
import org.astral.findmaimaiultra.ui.MainActivity;
|
||||||
|
import org.astral.findmaimaiultra.utill.FileUtils;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
import java.util.ArrayList;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.Collections;
|
import java.util.*;
|
||||||
import java.util.Comparator;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.List;
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
public class MusicFragment extends Fragment {
|
public class MusicFragment extends Fragment {
|
||||||
private FragmentMusicBinding binding;
|
private FragmentMusicBinding binding;
|
||||||
@@ -46,9 +59,14 @@ public class MusicFragment extends Fragment {
|
|||||||
private SharedPreferences scorePrefs;
|
private SharedPreferences scorePrefs;
|
||||||
private RecyclerView recyclerView;
|
private RecyclerView recyclerView;
|
||||||
private MusicRatingAdapter adapter;
|
private MusicRatingAdapter adapter;
|
||||||
|
private SuggestMusicRatingAdapter adapterSuggest;
|
||||||
|
|
||||||
private List<UserMusicList> musicSongsRatings;
|
private List<UserMusicList> musicSongsRatings;
|
||||||
private List<MusicRating> musicRatings = new ArrayList<>();
|
private List<MusicRating> musicRatings = new ArrayList<>();
|
||||||
private String userId;
|
private String userId;
|
||||||
|
private int iconId;
|
||||||
|
private String username;
|
||||||
|
private static Map<Integer, Song> songs = new HashMap<>();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
@@ -101,21 +119,184 @@ public class MusicFragment extends Fragment {
|
|||||||
ViewGroup container, Bundle savedInstanceState) {
|
ViewGroup container, Bundle savedInstanceState) {
|
||||||
MusicViewModel musicViewModel =
|
MusicViewModel musicViewModel =
|
||||||
new ViewModelProvider(this).get(MusicViewModel.class);
|
new ViewModelProvider(this).get(MusicViewModel.class);
|
||||||
|
SharedPreferences settingProperties = requireActivity().getSharedPreferences("setting", Context.MODE_PRIVATE);
|
||||||
|
username = settingProperties.getString("paikaname", "");
|
||||||
|
if (settingProperties.contains("userName")) {
|
||||||
|
username = settingProperties.getString("userName", "");
|
||||||
|
SharedPreferences.Editor editorM = setting.edit();
|
||||||
|
editorM.putString("paikaname",username);
|
||||||
|
editorM.commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
iconId = settingProperties.getInt("iconId", 0);
|
||||||
|
|
||||||
binding = FragmentMusicBinding.inflate(inflater, container, false);
|
binding = FragmentMusicBinding.inflate(inflater, container, false);
|
||||||
View root = binding.getRoot();
|
View root = binding.getRoot();
|
||||||
|
|
||||||
recyclerView = binding.getRoot().findViewById(R.id.recyclerView);
|
recyclerView = binding.getRoot().findViewById(R.id.recyclerView);
|
||||||
recyclerView.setLayoutManager(new GridLayoutManager(getContext(), 2)); // 一行显示两个
|
recyclerView.setLayoutManager(new GridLayoutManager(getContext(), 2)); // 一行显示两个
|
||||||
|
|
||||||
|
if (setting.getString("image_uri", null) != null ) {
|
||||||
|
try {
|
||||||
|
File backgroundFile = FileUtils.getBackground(requireContext(), "background.jpg");
|
||||||
|
|
||||||
|
if (!backgroundFile.exists()) {
|
||||||
|
Toast.makeText(requireContext(), "文件不存在,请先设置背景图片", Toast.LENGTH_SHORT).show();
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
|
Bitmap bitmap = BitmapFactory.decodeFile(backgroundFile.getAbsolutePath());
|
||||||
|
|
||||||
|
if (bitmap != null) {
|
||||||
|
// 获取RecyclerView的尺寸
|
||||||
|
int recyclerViewWidth = 0;
|
||||||
|
int recyclerViewHeight = 0;
|
||||||
|
recyclerViewWidth = recyclerView.getWidth();
|
||||||
|
recyclerViewHeight = recyclerView.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 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);
|
||||||
|
|
||||||
|
// 设置recyclerView的背景
|
||||||
|
recyclerView.setBackground(bitmapDrawable);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// 如果RecyclerView的尺寸未确定,可以使用ViewTreeObserver来监听尺寸变化
|
||||||
|
recyclerView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
|
||||||
|
@Override
|
||||||
|
public void onGlobalLayout() {
|
||||||
|
recyclerView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
|
||||||
|
int recyclerViewWidth = 0;
|
||||||
|
int recyclerViewHeight = 0;
|
||||||
|
recyclerViewWidth = recyclerView.getWidth();
|
||||||
|
recyclerViewHeight = recyclerView.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);
|
||||||
|
recyclerView.setBackground(bitmapDrawable);
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
|
||||||
|
Toast.makeText(requireContext(), "图片加载失败,权限出错!", Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
adapter = new MusicRatingAdapter(musicRatings);
|
adapter = new MusicRatingAdapter(musicRatings);
|
||||||
adapter.setOnItemClickListener(musicRating -> {
|
adapter.setOnItemClickListener(musicRating -> {
|
||||||
showMusicDetailDialog(musicRating);
|
showMusicDetailDialog(musicRating);
|
||||||
});
|
});
|
||||||
|
|
||||||
recyclerView.setAdapter(adapter);
|
recyclerView.setAdapter(adapter);
|
||||||
FloatingActionButton f = binding.fab;
|
FloatingActionButton f = binding.fab;
|
||||||
f.setOnClickListener(view -> {
|
f.setOnClickListener(view -> {
|
||||||
showOptionsDialog();
|
showOptionsDialog();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
ImageView user_avatar = binding.useravatar ;
|
||||||
|
Glide.with(this)
|
||||||
|
.load("https://assets2.lxns.net/maimai/icon/" + iconId +".png")
|
||||||
|
.into(user_avatar);
|
||||||
|
TextView user_name = binding.username;
|
||||||
|
user_name.setText(username);
|
||||||
|
if (!(iconId==0)){
|
||||||
|
MaterialButton login = binding.login;
|
||||||
|
login.setVisibility(View.GONE);
|
||||||
|
Intent loginIntent = new Intent(getActivity(), LinkQQBot.class);
|
||||||
|
login.setOnClickListener(view -> {
|
||||||
|
startActivity(loginIntent);
|
||||||
|
});
|
||||||
|
}else{
|
||||||
|
MaterialButton login = binding.login;
|
||||||
|
Intent loginIntent = new Intent(getActivity(), LinkQQBot.class);
|
||||||
|
login.setOnClickListener(view -> {
|
||||||
|
startActivity(loginIntent);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
dataanlysis();
|
||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -318,4 +499,227 @@ public class MusicFragment extends Fragment {
|
|||||||
musicRatings.addAll(filteredList);
|
musicRatings.addAll(filteredList);
|
||||||
adapter.notifyDataSetChanged();
|
adapter.notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
|
private void dataanlysis() {
|
||||||
|
ExecutorService executor = Executors.newSingleThreadExecutor();
|
||||||
|
Handler handler = new Handler(Looper.getMainLooper());
|
||||||
|
|
||||||
|
executor.execute(() -> {
|
||||||
|
// Perform data processing in the background
|
||||||
|
DataAnalyzer dataAnalyzer = new DataAnalyzer();
|
||||||
|
|
||||||
|
|
||||||
|
try {
|
||||||
|
InputStream inputStream = requireContext().getAssets().open("musicLike.json");
|
||||||
|
int size = inputStream.available();
|
||||||
|
byte[] buffer = new byte[size];
|
||||||
|
inputStream.read(buffer);
|
||||||
|
inputStream.close();
|
||||||
|
String json = new String(buffer, StandardCharsets.UTF_8);
|
||||||
|
dataAnalyzer = new Gson().fromJson(json,DataAnalyzer.class);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
InputStream inputStream = requireContext().getAssets().open("songs_cache.json");
|
||||||
|
int size = inputStream.available();
|
||||||
|
byte[] buffer = new byte[size];
|
||||||
|
inputStream.read(buffer);
|
||||||
|
inputStream.close();
|
||||||
|
String json = new String(buffer, StandardCharsets.UTF_8);
|
||||||
|
Type type = new TypeToken<Map<String, Song>>() {}.getType();
|
||||||
|
Map<String, Song> loadedSongs = new Gson().fromJson(json, type);
|
||||||
|
|
||||||
|
// 手动转换 key 为 Integer 并放入全局 map
|
||||||
|
for (Map.Entry<String, Song> entry : loadedSongs.entrySet()) {
|
||||||
|
Integer id = Integer.parseInt(entry.getKey());
|
||||||
|
songs.put(id, entry.getValue());
|
||||||
|
songs.put(id + 10000, entry.getValue()); // 如果你需要 standard 版本
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
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<Integer> ids= new ArrayList<>();
|
||||||
|
int worstRating = b50.get(b50.size() - 1).getRating();
|
||||||
|
|
||||||
|
List<MusicRating> suggestMusicRatingList = new ArrayList<>();
|
||||||
|
for (int x = 0; x < 50; x++) {
|
||||||
|
total += b50.get(x).getRating();
|
||||||
|
MusicRating m = b100.get(x);
|
||||||
|
int nowache = m.getAchievement();
|
||||||
|
int target = 0;
|
||||||
|
if (nowache >= 1000000 && nowache < 10050000) {
|
||||||
|
target = 1005001;
|
||||||
|
} else if (nowache >= 995000 && nowache < 10000000) {
|
||||||
|
target = 1000001;
|
||||||
|
} else if (nowache >= 990000 && nowache < 995000) {
|
||||||
|
target = 995001;
|
||||||
|
} else if (nowache >= 980000 && nowache < 990000) {
|
||||||
|
target = 990001;
|
||||||
|
} else if (nowache >= 970000 && nowache < 980000) {
|
||||||
|
target = 980001;
|
||||||
|
}
|
||||||
|
double b1 = (double) target / 10000;
|
||||||
|
int targetRating = getRatingChart(m.getLevel_info(), b1);
|
||||||
|
if (targetRating > worstRating) {
|
||||||
|
m.setExtNum1(target);
|
||||||
|
if (m.getMusicId() > 10000) {
|
||||||
|
ids.add(m.getMusicId()-10000);
|
||||||
|
}else {
|
||||||
|
ids.add(m.getMusicId());
|
||||||
|
}
|
||||||
|
m.setExtNum2(targetRating);
|
||||||
|
suggestMusicRatingList.add(m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
List<EasySong> easySongs = new ArrayList<>();
|
||||||
|
//看看别人打什么
|
||||||
|
Log.d("TOP",total + "");
|
||||||
|
if (total>=16000) {
|
||||||
|
easySongs = dataAnalyzer.getEasySongs().get("16000");
|
||||||
|
}else if (total>=15500) {
|
||||||
|
easySongs = dataAnalyzer.getEasySongs().get("15500");
|
||||||
|
}else if (total>=15000) {
|
||||||
|
easySongs = dataAnalyzer.getEasySongs().get("15000");
|
||||||
|
}else if (total>=14500) {
|
||||||
|
easySongs = dataAnalyzer.getEasySongs().get("14500");
|
||||||
|
}else if (total>=14000) {
|
||||||
|
easySongs = dataAnalyzer.getEasySongs().get("14000");
|
||||||
|
}else if (total>=13000) {
|
||||||
|
easySongs = dataAnalyzer.getEasySongs().get("13000");
|
||||||
|
}else if (total>=12000) {
|
||||||
|
easySongs = dataAnalyzer.getEasySongs().get("12000");
|
||||||
|
}else if (total>=11000) {
|
||||||
|
easySongs = dataAnalyzer.getEasySongs().get("11000");
|
||||||
|
}
|
||||||
|
for (int x = 0 ; x < easySongs.size();x ++) {
|
||||||
|
EasySong e = easySongs.get(x);
|
||||||
|
if (e.getPercent()>0.1) {
|
||||||
|
if (ids.contains(e.getId())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
;
|
||||||
|
double diff = songs.get(e.getId()).getDifficulties().get(e.getType())[e.getLevel()].getLevel_value();
|
||||||
|
double b = 99.0000;
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
b = b + 0.5 * (i - 1);
|
||||||
|
int ra = getRatingChart(diff, b);
|
||||||
|
if (ra > worstRating) {
|
||||||
|
MusicRating musicRating = new MusicRating();
|
||||||
|
musicRating.setMusicId(e.getId());
|
||||||
|
musicRating.setMusicName(e.getTitle());
|
||||||
|
musicRating.setExtNum1((int)(b*10000));
|
||||||
|
musicRating.setExtNum2(ra);
|
||||||
|
musicRating.setRating(0);
|
||||||
|
musicRating.setAchievement(0);
|
||||||
|
musicRating.setLevel_info(diff);
|
||||||
|
musicRating.setType(e.getType());
|
||||||
|
suggestMusicRatingList.add(musicRating);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Update UI on the main thread
|
||||||
|
handler.post(() -> {
|
||||||
|
RecyclerView suggest = binding.getRoot().findViewById(R.id.suggestion);
|
||||||
|
suggest.setLayoutManager(new GridLayoutManager(getContext(), 1));
|
||||||
|
|
||||||
|
adapterSuggest = new SuggestMusicRatingAdapter(suggestMusicRatingList);
|
||||||
|
suggest.setAdapter(adapterSuggest);
|
||||||
|
adapterSuggest.notifyDataSetChanged();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
public int getRatingChart(double a1, double b1) {
|
||||||
|
double sys = 22.4;
|
||||||
|
if (b1 >= 100.5000) {
|
||||||
|
return (int) (a1 * 22.512);
|
||||||
|
}
|
||||||
|
if (b1 == 100.4999) {
|
||||||
|
sys = 22.2;
|
||||||
|
} else if (b1 >= 100.0000) {
|
||||||
|
sys = 21.6;
|
||||||
|
} else if (b1 == 99.9999) {
|
||||||
|
sys = 21.4;
|
||||||
|
} else if (b1 >= 99.5000) {
|
||||||
|
sys = 21.1;
|
||||||
|
} else if (b1 >= 99.0000) {
|
||||||
|
sys = 20.8;
|
||||||
|
} else if (b1 >= 98.0000) {
|
||||||
|
sys = 20.3;
|
||||||
|
} else if (b1 >= 97.0000) {
|
||||||
|
sys = 20.0;
|
||||||
|
} else {
|
||||||
|
sys = 0;
|
||||||
|
}
|
||||||
|
return (int) (a1 * sys * b1 / 100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class DataAnalyzer {
|
||||||
|
Map<String, List<EasySong>> easySongs = new HashMap<>();
|
||||||
|
|
||||||
|
public Map<String, List<EasySong>> getEasySongs() {
|
||||||
|
return easySongs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEasySongs(Map<String, List<EasySong>> easySongs) {
|
||||||
|
this.easySongs = easySongs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class EasySong {
|
||||||
|
private String title;
|
||||||
|
private int level;
|
||||||
|
private float percent;
|
||||||
|
private int id;
|
||||||
|
private String type;
|
||||||
|
|
||||||
|
public String getTitle() {
|
||||||
|
return title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTitle(String title) {
|
||||||
|
this.title = title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getLevel() {
|
||||||
|
return level;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLevel(int level) {
|
||||||
|
this.level = level;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getPercent() {
|
||||||
|
return percent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPercent(float percent) {
|
||||||
|
this.percent = percent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(int id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setType(String type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -16,8 +16,6 @@ import android.webkit.WebViewClient;
|
|||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
import androidx.activity.result.ActivityResultLauncher;
|
|
||||||
import androidx.activity.result.contract.ActivityResultContracts;
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.core.app.ActivityCompat;
|
import androidx.core.app.ActivityCompat;
|
||||||
import androidx.core.content.ContextCompat;
|
import androidx.core.content.ContextCompat;
|
||||||
@@ -32,17 +30,14 @@ import org.astral.findmaimaiultra.been.Release;
|
|||||||
import org.astral.findmaimaiultra.databinding.FragmentSlideshowBinding;
|
import org.astral.findmaimaiultra.databinding.FragmentSlideshowBinding;
|
||||||
import org.astral.findmaimaiultra.service.GitHubApiService;
|
import org.astral.findmaimaiultra.service.GitHubApiService;
|
||||||
import org.astral.findmaimaiultra.ui.ImagePickerListener;
|
import org.astral.findmaimaiultra.ui.ImagePickerListener;
|
||||||
import org.astral.findmaimaiultra.ui.LinkQQBot;
|
import org.astral.findmaimaiultra.ui.login.LinkQQBot;
|
||||||
import org.astral.findmaimaiultra.utill.GitHubApiClient;
|
import org.astral.findmaimaiultra.utill.GitHubApiClient;
|
||||||
import org.w3c.dom.Text;
|
|
||||||
import retrofit2.Call;
|
import retrofit2.Call;
|
||||||
import retrofit2.Callback;
|
import retrofit2.Callback;
|
||||||
import retrofit2.Response;
|
import retrofit2.Response;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
import static android.app.Activity.RESULT_OK;
|
|
||||||
|
|
||||||
public class SlideshowFragment extends Fragment {
|
public class SlideshowFragment extends Fragment {
|
||||||
private SharedPreferences settingProperties;
|
private SharedPreferences settingProperties;
|
||||||
private static final int REQUEST_CODE_PERMISSIONS = 1001;
|
private static final int REQUEST_CODE_PERMISSIONS = 1001;
|
||||||
|
|||||||
@@ -41,7 +41,7 @@
|
|||||||
android:id="@+id/key"
|
android:id="@+id/key"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:hint="key"/>
|
android:hint="用户邮箱"/>
|
||||||
</com.google.android.material.textfield.TextInputLayout>
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
<com.google.android.material.textfield.TextInputLayout
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
@@ -53,11 +53,11 @@
|
|||||||
android:id="@+id/safecode"
|
android:id="@+id/safecode"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:hint="安全码"/>
|
android:hint="2fa应用内的6位数字代码(注册不用填)"/>
|
||||||
</com.google.android.material.textfield.TextInputLayout>
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton android:layout_width="match_parent"
|
<com.google.android.material.button.MaterialButton android:layout_width="match_parent"
|
||||||
android:text="绑定qq机器人"
|
android:text="登录/注册 账号"
|
||||||
android:textColor="@android:color/white"
|
android:textColor="@android:color/white"
|
||||||
|
|
||||||
android:id="@+id/bangding"
|
android:id="@+id/bangding"
|
||||||
|
|||||||
@@ -158,7 +158,7 @@
|
|||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="踩" android:paddingLeft="16sp"
|
android:text="踩" android:paddingLeft="16sp"
|
||||||
android:layout_marginLeft="2mm"
|
android:layout_marginLeft="1mm"
|
||||||
android:layout_centerInParent="true"/>
|
android:layout_centerInParent="true"/>
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/list"
|
android:id="@+id/list"
|
||||||
@@ -166,7 +166,7 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:paddingLeft="16sp"
|
android:paddingLeft="16sp"
|
||||||
android:text="评论"
|
android:text="评论"
|
||||||
android:layout_marginLeft="2mm"
|
android:layout_marginLeft="1mm"
|
||||||
android:layout_centerInParent="true"/>
|
android:layout_centerInParent="true"/>
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/move"
|
android:id="@+id/move"
|
||||||
@@ -174,7 +174,7 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:paddingLeft="16sp"
|
android:paddingLeft="16sp"
|
||||||
android:text="移动"
|
android:text="移动"
|
||||||
android:layout_marginLeft="2mm"
|
android:layout_marginLeft="1mm"
|
||||||
android:layout_centerInParent="true"/>
|
android:layout_centerInParent="true"/>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
<LinearLayout android:layout_width="match_parent" android:paddingLeft="16sp" android:layout_height="wrap_content" android:orientation="horizontal">
|
<LinearLayout android:layout_width="match_parent" android:paddingLeft="16sp" android:layout_height="wrap_content" android:orientation="horizontal">
|
||||||
|
|||||||
@@ -14,7 +14,8 @@
|
|||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent" />
|
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="1.0"
|
||||||
|
app:layout_constraintVertical_bias="0.0"/>
|
||||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||||
android:id="@+id/fab"
|
android:id="@+id/fab"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
@@ -26,4 +27,95 @@
|
|||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
tools:ignore="MissingConstraints" />
|
tools:ignore="MissingConstraints" />
|
||||||
|
|
||||||
|
|
||||||
|
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent">
|
||||||
|
|
||||||
|
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||||
|
|
||||||
|
android:id="@+id/bottom_sheet"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:minHeight="100dp"
|
||||||
|
android:background="@android:color/white"
|
||||||
|
app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior">
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/bac"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:paddingBottom="16dp"
|
||||||
|
tools:ignore="MissingConstraints">
|
||||||
|
|
||||||
|
<!-- 用户头像 -->
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/useravatar"
|
||||||
|
android:layout_width="50dp"
|
||||||
|
android:layout_height="50dp"
|
||||||
|
android:layout_marginEnd="16dp" />
|
||||||
|
|
||||||
|
<!-- 用户名容器 -->
|
||||||
|
<FrameLayout
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="@color/white"
|
||||||
|
>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/username"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="未绑定"
|
||||||
|
android:textSize="20sp"
|
||||||
|
android:textColor="@color/textcolorPrimary"
|
||||||
|
android:gravity="center"
|
||||||
|
android:layout_gravity="center_vertical|start"/> <!-- 距离顶部4dp -->
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
<com.google.android.material.button.MaterialButton android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:id="@+id/login"
|
||||||
|
android:text="登录"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:backgroundTint="@color/colorPrimary"
|
||||||
|
android:layout_marginBottom="16dp"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:layout_gravity="center_horizontal"/>
|
||||||
|
<TextView android:layout_width="match_parent" android:layout_height="wrap_content"
|
||||||
|
android:textColor="@color/textcolorPrimary"
|
||||||
|
android:text="⭐推分建议⭐"
|
||||||
|
android:padding="8dp"
|
||||||
|
android:id="@+id/su"
|
||||||
|
android:textSize="18sp"/>
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/suggestion"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="300dp"
|
||||||
|
app:layout_constraintTop_toTopOf="@id/su"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||||
|
|
||||||
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|||||||
@@ -163,7 +163,7 @@
|
|||||||
android:id="@+id/openQQbot"
|
android:id="@+id/openQQbot"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="#QQ机器人相关#"
|
android:text="#账号#"
|
||||||
android:textColor="@android:color/white"
|
android:textColor="@android:color/white"
|
||||||
|
|
||||||
android:backgroundTint="?attr/colorPrimary"
|
android:backgroundTint="?attr/colorPrimary"
|
||||||
|
|||||||
11
app/src/main/res/layout/fullscreen_webview_dialog.xml
Normal file
11
app/src/main/res/layout/fullscreen_webview_dialog.xml
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
<?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">
|
||||||
|
|
||||||
|
<WebView
|
||||||
|
android:id="@+id/webView"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent" />
|
||||||
|
</LinearLayout>
|
||||||
58
app/src/main/res/layout/item_suggest_music_rating.xml
Normal file
58
app/src/main/res/layout/item_suggest_music_rating.xml
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.cardview.widget.CardView
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:cardCornerRadius="8dp"
|
||||||
|
app:cardElevation="4dp"
|
||||||
|
android:layout_margin="2dp">
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<!-- 图片部分 -->
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/backgroundLayout"
|
||||||
|
android:layout_width="140dp"
|
||||||
|
android:layout_height="140dp"
|
||||||
|
android:scaleType="centerCrop"
|
||||||
|
android:layout_alignParentStart="true"/>
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="8dp"
|
||||||
|
android:layout_toEndOf="@id/backgroundLayout"
|
||||||
|
android:layout_centerVertical="true">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/musicName"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textSize="18sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:ellipsize="end" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/level"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/ach"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/achievementImage"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:scaleType="centerInside" />
|
||||||
|
</LinearLayout>
|
||||||
|
</RelativeLayout>
|
||||||
|
</androidx.cardview.widget.CardView>
|
||||||
@@ -34,7 +34,7 @@
|
|||||||
<string name="navigation_drawer_close">Close navigation drawer</string>
|
<string name="navigation_drawer_close">Close navigation drawer</string>
|
||||||
<string name="menu_home">主页</string>
|
<string name="menu_home">主页</string>
|
||||||
<string name="menu_gallery">地图</string>
|
<string name="menu_gallery">地图</string>
|
||||||
<string name="menu_music">歌曲成绩</string>
|
<string name="menu_music">账号</string>
|
||||||
<string name="menu_slideshow">设置</string>
|
<string name="menu_slideshow">设置</string>
|
||||||
<string name="nav_header_title">FindMaimaiDX</string>
|
<string name="nav_header_title">FindMaimaiDX</string>
|
||||||
<string name="nav_header_subtitle">Reisa</string>
|
<string name="nav_header_subtitle">Reisa</string>
|
||||||
|
|||||||
Reference in New Issue
Block a user