@ -0,0 +1,15 @@
|
||||
*.iml
|
||||
.gradle
|
||||
/local.properties
|
||||
/.idea/caches
|
||||
/.idea/libraries
|
||||
/.idea/modules.xml
|
||||
/.idea/workspace.xml
|
||||
/.idea/navEditor.xml
|
||||
/.idea/assetWizardSettings.xml
|
||||
.DS_Store
|
||||
/build
|
||||
/captures
|
||||
.externalNativeBuild
|
||||
.cxx
|
||||
local.properties
|
||||
@ -0,0 +1,3 @@
|
||||
# 默认忽略的文件
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
@ -0,0 +1 @@
|
||||
My Application
|
||||
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CompilerConfiguration">
|
||||
<bytecodeTargetLevel target="11" />
|
||||
</component>
|
||||
</project>
|
||||
@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="deploymentTargetDropDown">
|
||||
<targetSelectedWithDropDown>
|
||||
<Target>
|
||||
<type value="QUICK_BOOT_TARGET" />
|
||||
<deviceKey>
|
||||
<Key>
|
||||
<type value="VIRTUAL_DEVICE_PATH" />
|
||||
<value value="C:\Users\20922\.android\avd\Pixel_6_Pro_API_33.avd" />
|
||||
</Key>
|
||||
</deviceKey>
|
||||
</Target>
|
||||
</targetSelectedWithDropDown>
|
||||
<timeTargetWasSelectedWithDropDown value="2025-09-29T07:20:17.026786700Z" />
|
||||
</component>
|
||||
</project>
|
||||
@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="GradleMigrationSettings" migrationVersion="1" />
|
||||
<component name="GradleSettings">
|
||||
<option name="linkedExternalProjectsSettings">
|
||||
<GradleProjectSettings>
|
||||
<option name="testRunner" value="GRADLE" />
|
||||
<option name="distributionType" value="DEFAULT_WRAPPED" />
|
||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||
<option name="modules">
|
||||
<set>
|
||||
<option value="$PROJECT_DIR$" />
|
||||
<option value="$PROJECT_DIR$/app" />
|
||||
</set>
|
||||
</option>
|
||||
</GradleProjectSettings>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
||||
@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="JDK" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||
</component>
|
||||
<component name="ProjectType">
|
||||
<option name="id" value="Android" />
|
||||
</component>
|
||||
</project>
|
||||
@ -0,0 +1 @@
|
||||
/build
|
||||
@ -0,0 +1,21 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# You can control the set of applied configuration files using the
|
||||
# proguardFiles setting in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
||||
# Uncomment this to preserve the line number information for
|
||||
# debugging stack traces.
|
||||
#-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
||||
@ -0,0 +1,26 @@
|
||||
package com.example.myapplication;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Instrumented test, which will execute on an Android device.
|
||||
*
|
||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||
*/
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class ExampleInstrumentedTest {
|
||||
@Test
|
||||
public void useAppContext() {
|
||||
// Context of the app under test.
|
||||
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
|
||||
assertEquals("com.example.myapplication", appContext.getPackageName());
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,155 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<uses-feature
|
||||
android:glEsVersion="0x00020000"
|
||||
android:required="true" />
|
||||
|
||||
<!-- 网络权限 -->
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
||||
|
||||
<!-- 高德地图SDK核心权限 -->
|
||||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
|
||||
<!-- <uses-permission android:name="android.permission.WRITE_SETTINGS" /> 注释掉:此权限仅系统应用可用 -->
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
|
||||
|
||||
<!-- 高德地图导航相关权限 -->
|
||||
<uses-permission android:name="android.permission.CAMERA" />
|
||||
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
<uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />
|
||||
|
||||
<!-- 课程提醒相关权限 -->
|
||||
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
|
||||
<uses-permission android:name="android.permission.USE_EXACT_ALARM" />
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||
<uses-permission android:name="android.permission.VIBRATE" />
|
||||
<uses-permission android:name="android.permission.USE_FULL_SCREEN_INTENT" />
|
||||
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
|
||||
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
|
||||
|
||||
<!-- 笔记图片相关权限 -->
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
|
||||
android:maxSdkVersion="32" />
|
||||
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:dataExtractionRules="@xml/data_extraction_rules"
|
||||
android:fullBackupContent="@xml/backup_rules"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/Theme.MyApplication"
|
||||
android:hardwareAccelerated="true"
|
||||
android:networkSecurityConfig="@xml/network_security_config"
|
||||
android:usesCleartextTraffic="true"
|
||||
tools:targetApi="31">
|
||||
|
||||
<!-- 高德地图API Key -->
|
||||
<meta-data
|
||||
android:name="com.amap.api.v2.apikey"
|
||||
android:value="0c0a6f3a57e257c8bf0d9c8202110a37" />
|
||||
|
||||
<!-- 高德地图服务配置 -->
|
||||
<service android:name="com.amap.api.location.APSService"></service>
|
||||
|
||||
<activity
|
||||
android:name=".HomeActivity"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:exported="false"
|
||||
android:hardwareAccelerated="true"
|
||||
android:configChanges="orientation|screenSize|keyboardHidden" />
|
||||
|
||||
<activity
|
||||
android:name=".LocationDetailsActivity"
|
||||
android:exported="false" />
|
||||
|
||||
<!-- 教务系统登录WebView -->
|
||||
<activity
|
||||
android:name=".WebViewActivity"
|
||||
android:exported="false"
|
||||
android:label="教务系统登录"
|
||||
android:hardwareAccelerated="true"
|
||||
android:configChanges="orientation|screenSize|keyboardHidden" />
|
||||
|
||||
<!-- 教务系统课表导入 -->
|
||||
<activity
|
||||
android:name=".EducationImportActivity"
|
||||
android:exported="false"
|
||||
android:label="教务系统课表导入"
|
||||
android:hardwareAccelerated="true"
|
||||
android:configChanges="orientation|screenSize|keyboardHidden" />
|
||||
|
||||
<!-- 课程提醒全屏弹窗 -->
|
||||
<activity
|
||||
android:name=".ReminderAlertActivity"
|
||||
android:exported="false"
|
||||
android:theme="@style/Theme.AppCompat.Dialog.Alert"
|
||||
android:excludeFromRecents="true"
|
||||
android:finishOnTaskLaunch="true" />
|
||||
|
||||
<!-- 课程提醒弹窗(微信样式) -->
|
||||
<activity
|
||||
android:name=".CourseReminderActivity"
|
||||
android:exported="false"
|
||||
android:theme="@style/ReminderDialogTheme"
|
||||
android:excludeFromRecents="true"
|
||||
android:showWhenLocked="true"
|
||||
android:turnScreenOn="true"
|
||||
android:launchMode="singleTop" />
|
||||
|
||||
<!-- 全屏笔记编辑器 -->
|
||||
<activity
|
||||
android:name=".NoteEditorActivity"
|
||||
android:exported="false"
|
||||
android:label="编辑笔记"
|
||||
android:hardwareAccelerated="true"
|
||||
android:configChanges="orientation|screenSize|keyboardHidden" />
|
||||
|
||||
<!-- 笔记阅读模式 -->
|
||||
<activity
|
||||
android:name=".NoteReaderActivity"
|
||||
android:exported="false"
|
||||
android:label="阅读笔记"
|
||||
android:hardwareAccelerated="true"
|
||||
android:configChanges="orientation|screenSize|keyboardHidden" />
|
||||
|
||||
<!-- FileProvider for sharing files -->
|
||||
<provider
|
||||
android:name="androidx.core.content.FileProvider"
|
||||
android:authorities="${applicationId}.fileprovider"
|
||||
android:exported="false"
|
||||
android:grantUriPermissions="true">
|
||||
<meta-data
|
||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||
android:resource="@xml/file_paths" />
|
||||
</provider>
|
||||
|
||||
<!-- 课程提醒接收器 -->
|
||||
<receiver
|
||||
android:name=".CourseReminderReceiver"
|
||||
android:enabled="true"
|
||||
android:exported="false" />
|
||||
|
||||
<receiver
|
||||
android:name=".ReminderReceiver"
|
||||
android:exported="false" />
|
||||
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
@ -0,0 +1,158 @@
|
||||
package com.example.myapplication;
|
||||
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
import android.widget.EditText;
|
||||
import android.text.Editable;
|
||||
import android.text.TextWatcher;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class GradeAdapter extends RecyclerView.Adapter<GradeAdapter.GradeViewHolder> {
|
||||
|
||||
private List<WebViewActivity.GradeItem> gradeItems;
|
||||
public interface OnItemUpdatedListener { void onScoreUpdated(); }
|
||||
private OnItemUpdatedListener onItemUpdatedListener;
|
||||
|
||||
public GradeAdapter() {
|
||||
this.gradeItems = new ArrayList<>();
|
||||
}
|
||||
|
||||
public void updateData(List<WebViewActivity.GradeItem> newItems) {
|
||||
this.gradeItems.clear();
|
||||
this.gradeItems.addAll(newItems);
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
public void setOnItemUpdatedListener(OnItemUpdatedListener listener) {
|
||||
this.onItemUpdatedListener = listener;
|
||||
}
|
||||
|
||||
public List<WebViewActivity.GradeItem> getItems() { return gradeItems; }
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public GradeViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
View view = LayoutInflater.from(parent.getContext())
|
||||
.inflate(R.layout.item_grade, parent, false);
|
||||
return new GradeViewHolder(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull GradeViewHolder holder, int position) {
|
||||
WebViewActivity.GradeItem item = gradeItems.get(position);
|
||||
|
||||
// 课程名称作为主标题
|
||||
String courseName = item.courseName != null && !item.courseName.isEmpty() ? item.courseName : "未知课程";
|
||||
holder.tvCourseName.setText(courseName);
|
||||
|
||||
// 课程编号
|
||||
String courseCode = item.courseCode != null && !item.courseCode.isEmpty() ? item.courseCode : "未知";
|
||||
holder.tvCourseCode.setText("编号: " + courseCode);
|
||||
|
||||
// 学分信息
|
||||
holder.tvCredit.setText("学分: " + (item.credit != null ? item.credit : "未知"));
|
||||
|
||||
// 成绩信息/输入切换
|
||||
boolean hasScore = item.score != null && !item.score.isEmpty();
|
||||
if (hasScore) {
|
||||
holder.tvScore.setVisibility(View.VISIBLE);
|
||||
holder.etScoreInput.setVisibility(View.GONE);
|
||||
holder.tvScore.setText("成绩: " + item.score);
|
||||
} else {
|
||||
holder.tvScore.setVisibility(View.GONE);
|
||||
holder.etScoreInput.setVisibility(View.VISIBLE);
|
||||
// 避免旧监听残留
|
||||
Object oldWatcher = holder.etScoreInput.getTag();
|
||||
if (oldWatcher instanceof TextWatcher) {
|
||||
holder.etScoreInput.removeTextChangedListener((TextWatcher) oldWatcher);
|
||||
}
|
||||
holder.etScoreInput.setText(item.score != null ? item.score : "");
|
||||
holder.etScoreInput.setHint("请输入成绩");
|
||||
|
||||
// 监听输入并计算绩点
|
||||
TextWatcher watcher = new TextWatcher() {
|
||||
@Override public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
|
||||
@Override public void onTextChanged(CharSequence s, int start, int before, int count) {}
|
||||
@Override public void afterTextChanged(Editable s) {
|
||||
String text = s.toString().trim();
|
||||
item.score = text;
|
||||
String gpa = computeGpaFromScore(text);
|
||||
item.gpa = gpa;
|
||||
holder.tvGpa.setText("绩点: " + (gpa != null && !gpa.isEmpty() ? gpa : "0"));
|
||||
if (onItemUpdatedListener != null) onItemUpdatedListener.onScoreUpdated();
|
||||
}
|
||||
};
|
||||
holder.etScoreInput.addTextChangedListener(watcher);
|
||||
holder.etScoreInput.setTag(watcher);
|
||||
}
|
||||
|
||||
// 绩点信息
|
||||
holder.tvGpa.setText("绩点: " + (item.gpa != null && !item.gpa.isEmpty() ? item.gpa : "未知"));
|
||||
|
||||
// 学年/建议修读学年
|
||||
holder.tvYear.setText((hasScore ? "学年: " : "建议修读学年: ") + (item.year != null && !item.year.isEmpty() ? item.year : "未知"));
|
||||
|
||||
// 课程性质信息
|
||||
holder.tvStatus.setText("课程性质: " + (item.status != null ? item.status : "未知"));
|
||||
|
||||
// 学期/建议修读学期
|
||||
holder.tvTerm.setText((hasScore ? "学期: " : "建议修读学期: ") + (item.term != null && !item.term.isEmpty() ? item.term : "未知"));
|
||||
}
|
||||
|
||||
private String computeGpaFromScore(String scoreText) {
|
||||
if (scoreText == null || scoreText.isEmpty()) return "";
|
||||
try {
|
||||
int score = Integer.parseInt(scoreText);
|
||||
if (score >= 90) return "4.0";
|
||||
if (score >= 85) return "3.7";
|
||||
if (score >= 82) return "3.3";
|
||||
if (score >= 78) return "3.0";
|
||||
if (score >= 75) return "2.7";
|
||||
if (score >= 72) return "2.3";
|
||||
if (score >= 68) return "2.0";
|
||||
if (score >= 66) return "1.7";
|
||||
if (score >= 64) return "1.5";
|
||||
if (score >= 60) return "1.0";
|
||||
return "0";
|
||||
} catch (NumberFormatException e) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return gradeItems.size();
|
||||
}
|
||||
|
||||
static class GradeViewHolder extends RecyclerView.ViewHolder {
|
||||
TextView tvCourseName;
|
||||
TextView tvCourseCode;
|
||||
TextView tvCredit;
|
||||
TextView tvScore;
|
||||
EditText etScoreInput;
|
||||
TextView tvGpa;
|
||||
TextView tvTerm;
|
||||
TextView tvYear;
|
||||
TextView tvStatus;
|
||||
|
||||
public GradeViewHolder(@NonNull View itemView) {
|
||||
super(itemView);
|
||||
tvCourseName = itemView.findViewById(R.id.tv_course_name);
|
||||
tvCourseCode = itemView.findViewById(R.id.tv_course_code);
|
||||
tvCredit = itemView.findViewById(R.id.tv_credit);
|
||||
tvScore = itemView.findViewById(R.id.tv_score);
|
||||
etScoreInput = itemView.findViewById(R.id.et_score_input);
|
||||
tvGpa = itemView.findViewById(R.id.tv_gpa);
|
||||
tvTerm = itemView.findViewById(R.id.tv_term);
|
||||
tvYear = itemView.findViewById(R.id.tv_year);
|
||||
tvStatus = itemView.findViewById(R.id.tv_status);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,62 @@
|
||||
package com.example.myapplication;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.cardview.widget.CardView;
|
||||
|
||||
public class HomeActivity extends AppCompatActivity {
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_home);
|
||||
|
||||
// 获取四个功能卡片
|
||||
CardView cardTimetable = findViewById(R.id.card_timetable);
|
||||
CardView cardNotes = findViewById(R.id.card_notes);
|
||||
CardView cardGrades = findViewById(R.id.card_grades);
|
||||
CardView cardCampus = findViewById(R.id.card_campus);
|
||||
|
||||
// 课表按钮点击事件
|
||||
cardTimetable.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Intent intent = new Intent(HomeActivity.this, MainActivity.class);
|
||||
intent.putExtra("fragment", "timetable");
|
||||
startActivity(intent);
|
||||
}
|
||||
});
|
||||
|
||||
// 笔记按钮点击事件
|
||||
cardNotes.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Intent intent = new Intent(HomeActivity.this, MainActivity.class);
|
||||
intent.putExtra("fragment", "notes");
|
||||
startActivity(intent);
|
||||
}
|
||||
});
|
||||
|
||||
// 成绩按钮点击事件
|
||||
cardGrades.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Intent intent = new Intent(HomeActivity.this, MainActivity.class);
|
||||
intent.putExtra("fragment", "grades");
|
||||
startActivity(intent);
|
||||
}
|
||||
});
|
||||
|
||||
// 校园导航按钮点击事件
|
||||
cardCampus.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Intent intent = new Intent(HomeActivity.this, MainActivity.class);
|
||||
intent.putExtra("fragment", "campus");
|
||||
startActivity(intent);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,61 @@
|
||||
package com.example.myapplication;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
public class MainActivity extends AppCompatActivity {
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
try {
|
||||
// Configure window for better OpenGL rendering
|
||||
Window window = getWindow();
|
||||
window.setFlags(WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
|
||||
WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
|
||||
|
||||
setContentView(R.layout.activity_main);
|
||||
|
||||
// 从Intent获取要显示的页面
|
||||
String fragmentType = getIntent().getStringExtra("fragment");
|
||||
|
||||
if (savedInstanceState == null) {
|
||||
Fragment fragment = null;
|
||||
|
||||
if ("notes".equals(fragmentType)) {
|
||||
fragment = new NotesFragment();
|
||||
} else if ("grades".equals(fragmentType)) {
|
||||
fragment = new GradesFragment();
|
||||
} else if ("campus".equals(fragmentType)) {
|
||||
fragment = new CampusNavFragmentSimplified();
|
||||
} else {
|
||||
// 默认显示课表页面
|
||||
fragment = new TimetableFragment();
|
||||
}
|
||||
|
||||
getSupportFragmentManager()
|
||||
.beginTransaction()
|
||||
.replace(R.id.fragment_container, fragment)
|
||||
.commit();
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
Toast.makeText(this, "应用初始化失败", Toast.LENGTH_LONG).show();
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
// 返回主页面
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,95 @@
|
||||
package com.example.myapplication;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class Note implements Serializable {
|
||||
private String id;
|
||||
private String title; // 笔记标题
|
||||
private String content; // 笔记内容
|
||||
private String courseId; // 关联的课程ID
|
||||
private String courseName; // 关联的课程名称
|
||||
private long createTime; // 创建时间
|
||||
private long modifyTime; // 修改时间
|
||||
private List<String> imagePaths; // 图片路径列表
|
||||
|
||||
public Note() {
|
||||
this.id = String.valueOf(System.currentTimeMillis());
|
||||
this.createTime = System.currentTimeMillis();
|
||||
this.modifyTime = System.currentTimeMillis();
|
||||
this.imagePaths = new ArrayList<>();
|
||||
}
|
||||
|
||||
public Note(String title, String content) {
|
||||
this();
|
||||
this.title = title;
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
public Note(String title, String content, String courseId, String courseName) {
|
||||
this(title, content);
|
||||
this.courseId = courseId;
|
||||
this.courseName = courseName;
|
||||
}
|
||||
|
||||
// Getters and Setters
|
||||
public String getId() { return id; }
|
||||
public void setId(String id) { this.id = id; }
|
||||
|
||||
public String getTitle() { return title; }
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
this.modifyTime = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
public String getContent() { return content; }
|
||||
public void setContent(String content) {
|
||||
this.content = content;
|
||||
this.modifyTime = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
public String getCourseId() { return courseId; }
|
||||
public void setCourseId(String courseId) {
|
||||
this.courseId = courseId;
|
||||
this.modifyTime = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
public String getCourseName() { return courseName; }
|
||||
public void setCourseName(String courseName) {
|
||||
this.courseName = courseName;
|
||||
this.modifyTime = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
public long getCreateTime() { return createTime; }
|
||||
public void setCreateTime(long createTime) { this.createTime = createTime; }
|
||||
|
||||
public long getModifyTime() { return modifyTime; }
|
||||
public void setModifyTime(long modifyTime) { this.modifyTime = modifyTime; }
|
||||
|
||||
public List<String> getImagePaths() { return imagePaths; }
|
||||
public void setImagePaths(List<String> imagePaths) {
|
||||
this.imagePaths = imagePaths != null ? imagePaths : new ArrayList<>();
|
||||
this.modifyTime = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
public void addImagePath(String imagePath) {
|
||||
if (this.imagePaths == null) {
|
||||
this.imagePaths = new ArrayList<>();
|
||||
}
|
||||
this.imagePaths.add(imagePath);
|
||||
this.modifyTime = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
public void removeImagePath(String imagePath) {
|
||||
if (this.imagePaths != null) {
|
||||
this.imagePaths.remove(imagePath);
|
||||
this.modifyTime = System.currentTimeMillis();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return title + (courseName != null ? " (" + courseName + ")" : "");
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,368 @@
|
||||
package com.example.myapplication;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.*;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class NotesFragment extends Fragment {
|
||||
|
||||
private RecyclerView rvNotes;
|
||||
private FloatingActionButton fabAddNote;
|
||||
private Spinner spinnerCourseFilter;
|
||||
private LinearLayout layoutEmpty;
|
||||
private com.google.android.material.textfield.TextInputLayout tilNoteSearch;
|
||||
private android.widget.EditText etNoteSearch;
|
||||
|
||||
private DataManager dataManager;
|
||||
private List<Note> allNotes;
|
||||
private List<Note> filteredNotes;
|
||||
private List<Course> courses;
|
||||
private NotesAdapter notesAdapter;
|
||||
|
||||
private String selectedCourseId = "";
|
||||
private String searchQuery = "";
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
View view = inflater.inflate(R.layout.fragment_notes, container, false);
|
||||
|
||||
initViews(view);
|
||||
setupData();
|
||||
setupListeners();
|
||||
setupRecyclerView();
|
||||
setupCourseFilter();
|
||||
loadNotes();
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
private void initViews(View view) {
|
||||
rvNotes = view.findViewById(R.id.rv_notes);
|
||||
fabAddNote = view.findViewById(R.id.fab_add_note);
|
||||
spinnerCourseFilter = view.findViewById(R.id.spinner_course_filter);
|
||||
layoutEmpty = view.findViewById(R.id.layout_empty);
|
||||
tilNoteSearch = view.findViewById(R.id.til_note_search);
|
||||
etNoteSearch = view.findViewById(R.id.et_note_search);
|
||||
}
|
||||
|
||||
private void setupData() {
|
||||
dataManager = new DataManager(getContext());
|
||||
allNotes = new ArrayList<>();
|
||||
filteredNotes = new ArrayList<>();
|
||||
courses = dataManager.getCourses();
|
||||
}
|
||||
|
||||
private void setupListeners() {
|
||||
fabAddNote.setOnClickListener(v -> {
|
||||
android.content.Intent intent = new android.content.Intent(getContext(), NoteEditorActivity.class);
|
||||
startActivity(intent);
|
||||
});
|
||||
|
||||
if (tilNoteSearch != null) {
|
||||
tilNoteSearch.setEndIconOnClickListener(v -> filterNotes());
|
||||
}
|
||||
if (etNoteSearch != null) {
|
||||
etNoteSearch.addTextChangedListener(new android.text.TextWatcher() {
|
||||
@Override public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
|
||||
@Override public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
searchQuery = s.toString().trim();
|
||||
filterNotes();
|
||||
}
|
||||
@Override public void afterTextChanged(android.text.Editable s) {}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void setupRecyclerView() {
|
||||
notesAdapter = new NotesAdapter(getContext(), filteredNotes);
|
||||
notesAdapter.setOnNoteClickListener(new NotesAdapter.OnNoteClickListener() {
|
||||
@Override
|
||||
public void onNoteClick(Note note) {
|
||||
// 打开阅读模式
|
||||
android.content.Intent intent = new android.content.Intent(getContext(), NoteReaderActivity.class);
|
||||
intent.putExtra(NoteReaderActivity.EXTRA_NOTE_ID, note.getId());
|
||||
startActivity(intent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNoteLongClick(Note note) {
|
||||
showNoteOptions(note);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEditClick(Note note) {
|
||||
// 打开编辑模式
|
||||
android.content.Intent intent = new android.content.Intent(getContext(), NoteEditorActivity.class);
|
||||
intent.putExtra(NoteEditorActivity.EXTRA_NOTE_ID, note.getId());
|
||||
startActivity(intent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeleteClick(Note note) {
|
||||
deleteNote(note);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResetOtherItems() {
|
||||
// 重置所有滑动状态
|
||||
notesAdapter.notifyDataSetChanged();
|
||||
}
|
||||
});
|
||||
rvNotes.setLayoutManager(new LinearLayoutManager(getContext()));
|
||||
rvNotes.setAdapter(notesAdapter);
|
||||
}
|
||||
|
||||
private void setupCourseFilter() {
|
||||
List<String> courseNames = new ArrayList<>();
|
||||
courseNames.add("全部课程");
|
||||
|
||||
List<String> courseIds = new ArrayList<>();
|
||||
courseIds.add("");
|
||||
|
||||
for (Course course : courses) {
|
||||
courseNames.add(course.getName());
|
||||
courseIds.add(course.getId());
|
||||
}
|
||||
|
||||
ArrayAdapter<String> adapter = new ArrayAdapter<>(getContext(),
|
||||
android.R.layout.simple_spinner_item, courseNames);
|
||||
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
||||
spinnerCourseFilter.setAdapter(adapter);
|
||||
|
||||
spinnerCourseFilter.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
|
||||
@Override
|
||||
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
|
||||
selectedCourseId = courseIds.get(position);
|
||||
filterNotes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNothingSelected(AdapterView<?> parent) {}
|
||||
});
|
||||
}
|
||||
|
||||
private void loadNotes() {
|
||||
allNotes = dataManager.getNotes();
|
||||
filterNotes();
|
||||
}
|
||||
|
||||
private void filterNotes() {
|
||||
filteredNotes.clear();
|
||||
String q = searchQuery == null ? "" : searchQuery.toLowerCase();
|
||||
for (Note note : allNotes) {
|
||||
boolean courseOk = selectedCourseId.isEmpty() || (note.getCourseId() != null && note.getCourseId().equals(selectedCourseId));
|
||||
if (!courseOk) continue;
|
||||
if (q.isEmpty()) {
|
||||
filteredNotes.add(note);
|
||||
} else {
|
||||
String title = note.getTitle() == null ? "" : note.getTitle().toLowerCase();
|
||||
String content = note.getContent() == null ? "" : note.getContent().toLowerCase();
|
||||
String course = note.getCourseName() == null ? "" : note.getCourseName().toLowerCase();
|
||||
if (title.contains(q) || content.contains(q) || course.contains(q)) {
|
||||
filteredNotes.add(note);
|
||||
}
|
||||
}
|
||||
}
|
||||
// 按修改时间倒序
|
||||
java.util.Collections.sort(filteredNotes, (a, b) -> Long.compare(b.getModifyTime(), a.getModifyTime()));
|
||||
notesAdapter.updateNotes(filteredNotes);
|
||||
updateEmptyView();
|
||||
}
|
||||
|
||||
private void updateEmptyView() {
|
||||
if (filteredNotes.isEmpty()) {
|
||||
rvNotes.setVisibility(View.GONE);
|
||||
layoutEmpty.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
rvNotes.setVisibility(View.VISIBLE);
|
||||
layoutEmpty.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
private void showAddNoteDialog(Note editNote) {
|
||||
View dialogView = LayoutInflater.from(getContext()).inflate(R.layout.dialog_add_note, null);
|
||||
|
||||
TextView tvDialogTitle = dialogView.findViewById(R.id.tv_dialog_title);
|
||||
EditText etNoteTitle = dialogView.findViewById(R.id.et_note_title);
|
||||
EditText etNoteContent = dialogView.findViewById(R.id.et_note_content);
|
||||
Spinner spinnerCourse = dialogView.findViewById(R.id.spinner_course);
|
||||
|
||||
// 设置标题
|
||||
tvDialogTitle.setText(editNote == null ? "添加笔记" : "编辑笔记");
|
||||
|
||||
// 设置课程选择器
|
||||
List<String> courseOptions = new ArrayList<>();
|
||||
courseOptions.add("无关联课程");
|
||||
|
||||
List<String> courseIdOptions = new ArrayList<>();
|
||||
courseIdOptions.add("");
|
||||
|
||||
for (Course course : courses) {
|
||||
courseOptions.add(course.getName());
|
||||
courseIdOptions.add(course.getId());
|
||||
}
|
||||
|
||||
ArrayAdapter<String> courseAdapter = new ArrayAdapter<>(getContext(),
|
||||
android.R.layout.simple_spinner_item, courseOptions);
|
||||
courseAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
||||
spinnerCourse.setAdapter(courseAdapter);
|
||||
|
||||
// 如果是编辑模式,填充现有数据
|
||||
if (editNote != null) {
|
||||
etNoteTitle.setText(editNote.getTitle());
|
||||
etNoteContent.setText(editNote.getContent());
|
||||
|
||||
// 设置课程选择
|
||||
if (editNote.getCourseId() != null) {
|
||||
for (int i = 0; i < courseIdOptions.size(); i++) {
|
||||
if (courseIdOptions.get(i).equals(editNote.getCourseId())) {
|
||||
spinnerCourse.setSelection(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AlertDialog dialog = new AlertDialog.Builder(getContext())
|
||||
.setView(dialogView)
|
||||
.create();
|
||||
|
||||
dialogView.findViewById(R.id.btn_cancel).setOnClickListener(v -> dialog.dismiss());
|
||||
|
||||
dialogView.findViewById(R.id.btn_save).setOnClickListener(v -> {
|
||||
String title = etNoteTitle.getText().toString().trim();
|
||||
String content = etNoteContent.getText().toString().trim();
|
||||
|
||||
if (title.isEmpty()) {
|
||||
Toast.makeText(getContext(), "请输入笔记标题", Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
|
||||
if (content.isEmpty()) {
|
||||
Toast.makeText(getContext(), "请输入笔记内容", Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
|
||||
String selectedCourseId = courseIdOptions.get(spinnerCourse.getSelectedItemPosition());
|
||||
String selectedCourseName = "";
|
||||
if (!selectedCourseId.isEmpty()) {
|
||||
selectedCourseName = courseOptions.get(spinnerCourse.getSelectedItemPosition());
|
||||
}
|
||||
|
||||
if (editNote == null) {
|
||||
// 添加新笔记
|
||||
Note newNote = new Note(title, content, selectedCourseId, selectedCourseName);
|
||||
dataManager.addNote(newNote);
|
||||
allNotes.add(newNote);
|
||||
Toast.makeText(getContext(), "笔记添加成功", Toast.LENGTH_SHORT).show();
|
||||
} else {
|
||||
// 编辑现有笔记
|
||||
editNote.setTitle(title);
|
||||
editNote.setContent(content);
|
||||
editNote.setCourseId(selectedCourseId);
|
||||
editNote.setCourseName(selectedCourseName);
|
||||
dataManager.saveNotes(allNotes);
|
||||
Toast.makeText(getContext(), "笔记修改成功", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
filterNotes();
|
||||
dialog.dismiss();
|
||||
});
|
||||
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
private void deleteNote(Note note) {
|
||||
new AlertDialog.Builder(getContext())
|
||||
.setTitle("删除笔记")
|
||||
.setMessage("确定要删除笔记《" + note.getTitle() + "》吗?")
|
||||
.setPositiveButton("删除", (dialog, which) -> {
|
||||
dataManager.deleteNote(note.getId());
|
||||
// 删除图片文件
|
||||
if (note.getImagePaths() != null) {
|
||||
for (String imagePath : note.getImagePaths()) {
|
||||
try {
|
||||
java.io.File file = new java.io.File(imagePath);
|
||||
if (file.exists()) {
|
||||
file.delete();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
allNotes.remove(note);
|
||||
filterNotes();
|
||||
Toast.makeText(getContext(), "笔记已删除", Toast.LENGTH_SHORT).show();
|
||||
})
|
||||
.setNegativeButton("取消", null)
|
||||
.show();
|
||||
}
|
||||
|
||||
private void showNoteDetails(Note note) {
|
||||
String details = note.getContent();
|
||||
String title = note.getTitle();
|
||||
if (note.getCourseName() != null && !note.getCourseName().isEmpty()) {
|
||||
title += " (" + note.getCourseName() + ")";
|
||||
}
|
||||
|
||||
new AlertDialog.Builder(getContext())
|
||||
.setTitle(title)
|
||||
.setMessage(details)
|
||||
.setPositiveButton("确定", null)
|
||||
.setNeutralButton("编辑", (dialog, which) -> showAddNoteDialog(note))
|
||||
.show();
|
||||
}
|
||||
|
||||
private void showNoteOptions(Note note) {
|
||||
String[] options = {"查看详情", "编辑笔记", "删除笔记"};
|
||||
|
||||
new AlertDialog.Builder(getContext())
|
||||
.setTitle(note.getTitle())
|
||||
.setItems(options, (dialog, which) -> {
|
||||
switch (which) {
|
||||
case 0:
|
||||
showNoteDetails(note);
|
||||
break;
|
||||
case 1:
|
||||
showAddNoteDialog(note);
|
||||
break;
|
||||
case 2:
|
||||
deleteNote(note);
|
||||
break;
|
||||
}
|
||||
})
|
||||
.show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
// 重新加载课程数据(可能有新增的课程)
|
||||
courses = dataManager.getCourses();
|
||||
setupCourseFilter();
|
||||
// 返回时刷新笔记列表
|
||||
loadNotes();
|
||||
// 重置所有滑动状态
|
||||
if (notesAdapter != null) {
|
||||
notesAdapter.notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,80 @@
|
||||
package com.example.myapplication;
|
||||
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
public class ReminderAlertActivity extends AppCompatActivity {
|
||||
|
||||
@Override
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
|
||||
setShowWhenLocked(true);
|
||||
setTurnScreenOn(true);
|
||||
}
|
||||
|
||||
getWindow().addFlags(
|
||||
android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
|
||||
| android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
|
||||
| android.view.WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
|
||||
| android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
|
||||
);
|
||||
|
||||
setFinishOnTouchOutside(false);
|
||||
|
||||
String courseName = getIntent().getStringExtra(ReminderReceiver.EXTRA_COURSE_NAME);
|
||||
String location = getIntent().getStringExtra(ReminderReceiver.EXTRA_COURSE_LOCATION);
|
||||
String teacher = getIntent().getStringExtra(ReminderReceiver.EXTRA_COURSE_TEACHER);
|
||||
|
||||
StringBuilder message = new StringBuilder();
|
||||
if (location != null && !location.isEmpty()) {
|
||||
message.append("上课地点:").append(location);
|
||||
}
|
||||
if (teacher != null && !teacher.isEmpty()) {
|
||||
if (message.length() > 0) {
|
||||
message.append("\n");
|
||||
}
|
||||
message.append("任课教师:").append(teacher);
|
||||
}
|
||||
if (message.length() > 0) {
|
||||
message.append("\n");
|
||||
}
|
||||
message.append("请准时到达教室,祝您上课顺利!");
|
||||
|
||||
new AlertDialog.Builder(this)
|
||||
.setTitle(courseName == null || courseName.isEmpty() ? "上课提醒" : "上课提醒:" + courseName)
|
||||
.setMessage(message.toString())
|
||||
.setCancelable(false)
|
||||
.setPositiveButton("知道了", (dialog, which) -> finish())
|
||||
.setNegativeButton("稍后提醒", (dialog, which) -> {
|
||||
// 五分钟后再次提醒
|
||||
Course course = findCourseById(getIntent().getStringExtra(ReminderReceiver.EXTRA_COURSE_ID));
|
||||
if (course != null) {
|
||||
ReminderScheduler.scheduleReminderInMinutes(this, course, 5);
|
||||
}
|
||||
finish();
|
||||
})
|
||||
.setOnCancelListener(dialog -> finish())
|
||||
.show();
|
||||
}
|
||||
|
||||
private Course findCourseById(String courseId) {
|
||||
if (courseId == null || courseId.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
DataManager dataManager = new DataManager(this);
|
||||
for (Course course : dataManager.getCourses()) {
|
||||
if (course != null && courseId.equals(course.getId())) {
|
||||
return course;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,265 @@
|
||||
package com.example.myapplication;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.RectF;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 简单地图视图组件
|
||||
* 在高德地图完全集成前提供基础的地图可视化功能
|
||||
*/
|
||||
public class SimpleMapView extends View {
|
||||
|
||||
private Paint paintBackground;
|
||||
private Paint paintGrid;
|
||||
private Paint paintCurrentLocation;
|
||||
private Paint paintDestination;
|
||||
private Paint paintPath;
|
||||
private Paint paintText;
|
||||
|
||||
private List<LocationPoint> locations;
|
||||
private LocationPoint currentLocation;
|
||||
private LocationPoint destination;
|
||||
|
||||
private float centerX = 400f;
|
||||
private float centerY = 400f;
|
||||
private float scale = 100000f; // 地图缩放比例
|
||||
|
||||
public interface OnLocationClickListener {
|
||||
void onLocationClicked(LocationPoint point);
|
||||
}
|
||||
|
||||
private OnLocationClickListener onLocationClickListener;
|
||||
|
||||
public SimpleMapView(Context context) {
|
||||
super(context);
|
||||
init();
|
||||
}
|
||||
|
||||
public SimpleMapView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
init();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
initPaints();
|
||||
initData();
|
||||
}
|
||||
|
||||
private void initPaints() {
|
||||
paintBackground = new Paint();
|
||||
paintBackground.setColor(getResources().getColor(R.color.accent_green_bg, null));
|
||||
paintBackground.setStyle(Paint.Style.FILL);
|
||||
|
||||
paintGrid = new Paint();
|
||||
paintGrid.setColor(getResources().getColor(R.color.divider, null));
|
||||
paintGrid.setStrokeWidth(1);
|
||||
paintGrid.setAlpha(100);
|
||||
|
||||
paintCurrentLocation = new Paint();
|
||||
paintCurrentLocation.setColor(getResources().getColor(R.color.primary, null));
|
||||
paintCurrentLocation.setStyle(Paint.Style.FILL);
|
||||
|
||||
paintDestination = new Paint();
|
||||
paintDestination.setColor(getResources().getColor(R.color.error, null));
|
||||
paintDestination.setStyle(Paint.Style.FILL);
|
||||
|
||||
paintPath = new Paint();
|
||||
paintPath.setColor(getResources().getColor(R.color.accent_orange_dark, null));
|
||||
paintPath.setStrokeWidth(6);
|
||||
paintPath.setStyle(Paint.Style.STROKE);
|
||||
|
||||
paintText = new Paint();
|
||||
paintText.setColor(Color.BLACK);
|
||||
paintText.setTextSize(24);
|
||||
paintText.setAntiAlias(true);
|
||||
}
|
||||
|
||||
private void initData() {
|
||||
locations = new ArrayList<>();
|
||||
|
||||
// 添加一些示例位置点(使用相对坐标)
|
||||
locations.add(new LocationPoint("图书馆", 0, 100, "📚"));
|
||||
locations.add(new LocationPoint("第一食堂", 150, 50, "🍽️"));
|
||||
locations.add(new LocationPoint("第二食堂", -100, 80, "🍽️"));
|
||||
locations.add(new LocationPoint("教学楼A", 80, -50, "🏫"));
|
||||
locations.add(new LocationPoint("教学楼B", 120, -80, "🏫"));
|
||||
locations.add(new LocationPoint("实验楼", -80, -100, "🔬"));
|
||||
locations.add(new LocationPoint("体育馆", -150, 20, "🏃"));
|
||||
locations.add(new LocationPoint("宿舍区", 50, 150, "🏠"));
|
||||
|
||||
// 设置默认当前位置
|
||||
currentLocation = new LocationPoint("校门口", 0, 0, "📍");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
super.onDraw(canvas);
|
||||
|
||||
int width = getWidth();
|
||||
int height = getHeight();
|
||||
|
||||
// 绘制背景
|
||||
canvas.drawRect(0, 0, width, height, paintBackground);
|
||||
|
||||
// 绘制网格
|
||||
drawGrid(canvas, width, height);
|
||||
|
||||
// 绘制路径
|
||||
if (currentLocation != null && destination != null) {
|
||||
drawPath(canvas);
|
||||
}
|
||||
|
||||
// 绘制位置点
|
||||
for (LocationPoint point : locations) {
|
||||
drawLocationPoint(canvas, point, paintCurrentLocation);
|
||||
}
|
||||
|
||||
// 绘制当前位置
|
||||
if (currentLocation != null) {
|
||||
drawLocationPoint(canvas, currentLocation, paintCurrentLocation);
|
||||
}
|
||||
|
||||
// 绘制目标位置
|
||||
if (destination != null) {
|
||||
drawLocationPoint(canvas, destination, paintDestination);
|
||||
}
|
||||
|
||||
// 绘制图例
|
||||
drawLegend(canvas, width, height);
|
||||
}
|
||||
|
||||
private void drawGrid(Canvas canvas, int width, int height) {
|
||||
int gridSize = 50;
|
||||
|
||||
// 垂直线
|
||||
for (int x = 0; x < width; x += gridSize) {
|
||||
canvas.drawLine(x, 0, x, height, paintGrid);
|
||||
}
|
||||
|
||||
// 水平线
|
||||
for (int y = 0; y < height; y += gridSize) {
|
||||
canvas.drawLine(0, y, width, y, paintGrid);
|
||||
}
|
||||
}
|
||||
|
||||
private void drawLocationPoint(Canvas canvas, LocationPoint point, Paint paint) {
|
||||
float screenX = centerX + point.x;
|
||||
float screenY = centerY - point.y; // Y轴翻转
|
||||
|
||||
// 绘制圆点
|
||||
canvas.drawCircle(screenX, screenY, 15, paint);
|
||||
|
||||
// 绘制标签
|
||||
String label = point.icon + " " + point.name;
|
||||
canvas.drawText(label, screenX - 50, screenY - 25, paintText);
|
||||
}
|
||||
|
||||
private void drawPath(Canvas canvas) {
|
||||
if (currentLocation == null || destination == null) return;
|
||||
|
||||
float startX = centerX + currentLocation.x;
|
||||
float startY = centerY - currentLocation.y;
|
||||
float endX = centerX + destination.x;
|
||||
float endY = centerY - destination.y;
|
||||
|
||||
canvas.drawLine(startX, startY, endX, endY, paintPath);
|
||||
}
|
||||
|
||||
private void drawLegend(Canvas canvas, int width, int height) {
|
||||
int legendX = 20;
|
||||
int legendY = height - 120;
|
||||
|
||||
// 绘制图例背景
|
||||
RectF legendRect = new RectF(legendX - 10, legendY - 10, legendX + 200, legendY + 80);
|
||||
Paint legendBg = new Paint();
|
||||
legendBg.setColor(Color.WHITE);
|
||||
legendBg.setAlpha(200);
|
||||
canvas.drawRect(legendRect, legendBg);
|
||||
|
||||
// 绘制图例内容
|
||||
canvas.drawText("📍 当前位置", legendX, legendY, paintText);
|
||||
canvas.drawText("🎯 目标位置", legendX, legendY + 25, paintText);
|
||||
canvas.drawText("📚🍽️🏫 校园位置", legendX, legendY + 50, paintText);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
if (event.getAction() == MotionEvent.ACTION_DOWN) {
|
||||
float touchX = event.getX();
|
||||
float touchY = event.getY();
|
||||
|
||||
// 检查是否点击了某个位置点
|
||||
LocationPoint clickedPoint = findClickedLocation(touchX, touchY);
|
||||
if (clickedPoint != null && onLocationClickListener != null) {
|
||||
onLocationClickListener.onLocationClicked(clickedPoint);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return super.onTouchEvent(event);
|
||||
}
|
||||
|
||||
private LocationPoint findClickedLocation(float touchX, float touchY) {
|
||||
for (LocationPoint point : locations) {
|
||||
float screenX = centerX + point.x;
|
||||
float screenY = centerY - point.y;
|
||||
|
||||
float distance = (float) Math.sqrt(
|
||||
Math.pow(touchX - screenX, 2) + Math.pow(touchY - screenY, 2)
|
||||
);
|
||||
|
||||
if (distance <= 30) { // 点击范围
|
||||
return point;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void setCurrentLocation(String name, float x, float y) {
|
||||
currentLocation = new LocationPoint(name, x, y, "📍");
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setDestination(String name, float x, float y) {
|
||||
destination = new LocationPoint(name, x, y, "🎯");
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setOnLocationClickListener(OnLocationClickListener listener) {
|
||||
this.onLocationClickListener = listener;
|
||||
}
|
||||
|
||||
public void addLocation(String name, float x, float y, String icon) {
|
||||
locations.add(new LocationPoint(name, x, y, icon));
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void clearDestination() {
|
||||
destination = null;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
/**
|
||||
* 位置点数据类
|
||||
*/
|
||||
public static class LocationPoint {
|
||||
public String name;
|
||||
public float x, y;
|
||||
public String icon;
|
||||
|
||||
public LocationPoint(String name, float x, float y, String icon) {
|
||||
this.name = name;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.icon = icon;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,30 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:endX="85.84757"
|
||||
android:endY="92.4963"
|
||||
android:startX="42.9492"
|
||||
android:startY="49.59793"
|
||||
android:type="linear">
|
||||
<item
|
||||
android:color="#44000000"
|
||||
android:offset="0.0" />
|
||||
<item
|
||||
android:color="#00000000"
|
||||
android:offset="1.0" />
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:fillType="nonZero"
|
||||
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
|
||||
android:strokeWidth="1"
|
||||
android:strokeColor="#00000000" />
|
||||
</vector>
|
||||
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="oval">
|
||||
<solid android:color="#80000000" />
|
||||
<size
|
||||
android:width="48dp"
|
||||
android:height="48dp" />
|
||||
</shape>
|
||||
@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="oval">
|
||||
<solid android:color="#EEEEEE" />
|
||||
</shape>
|
||||
|
||||
|
||||
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="oval">
|
||||
<size android:width="56dp" android:height="56dp" />
|
||||
<solid android:color="@color/error" />
|
||||
<padding android:left="0dp" android:top="0dp" android:right="0dp" android:bottom="0dp" />
|
||||
</shape>
|
||||
|
||||
|
||||
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="oval">
|
||||
<size android:width="56dp" android:height="56dp" />
|
||||
<solid android:color="@color/primary" />
|
||||
<padding android:left="0dp" android:top="0dp" android:right="0dp" android:bottom="0dp" />
|
||||
</shape>
|
||||
|
||||
|
||||
@ -0,0 +1,170 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
<path
|
||||
android:fillColor="#3DDC84"
|
||||
android:pathData="M0,0h108v108h-108z" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M9,0L9,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,0L19,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M29,0L29,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M39,0L39,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M49,0L49,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M59,0L59,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M69,0L69,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M79,0L79,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M89,0L89,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M99,0L99,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,9L108,9"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,19L108,19"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,29L108,29"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,39L108,39"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,49L108,49"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,59L108,59"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,69L108,69"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,79L108,79"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,89L108,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,99L108,99"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,29L89,29"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,39L89,39"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,49L89,49"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,59L89,59"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,69L89,69"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,79L89,79"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M29,19L29,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M39,19L39,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M49,19L49,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M59,19L59,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M69,19L69,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M79,19L79,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
</vector>
|
||||
@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FFFFFFFF"
|
||||
android:pathData="M19.14,12.94c0.04,-0.31 0.06,-0.63 0.06,-0.94s-0.02,-0.63 -0.06,-0.94l2.03,-1.58c0.18,-0.14 0.23,-0.4 0.12,-0.61l-1.92,-3.32c-0.11,-0.21 -0.36,-0.3 -0.58,-0.22l-2.39,0.96c-0.5,-0.38 -1.04,-0.7 -1.64,-0.94L14.5,2.5c-0.02,-0.23 -0.22,-0.41 -0.45,-0.41h-3.1c-0.23,0 -0.43,0.18 -0.45,0.41L10,4.33c-0.59,0.24 -1.14,0.56 -1.64,0.94L5.97,4.31c-0.22,-0.09 -0.47,0.01 -0.58,0.22L3.47,7.85c-0.11,0.21 -0.06,0.47 0.12,0.61l2.03,1.58c-0.04,0.31 -0.06,0.63 -0.06,0.94s0.02,0.63 0.06,0.94l-2.03,1.58c-0.18,0.14 -0.23,0.4 -0.12,0.61l1.92,3.32c0.11,0.21 0.36,0.3 0.58,0.22l2.39,-0.96c0.5,0.38 1.04,0.7 1.64,0.94l0.5,1.83c0.02,0.23 0.22,0.41 0.45,0.41h3.1c0.23,0 0.43,-0.18 0.45,-0.41l0.5,-1.83c0.59,-0.24 1.14,-0.56 1.64,-0.94l2.39,0.96c0.22,0.09 0.47,-0.01 0.58,-0.22l1.92,-3.32c0.11,-0.21 0.06,-0.47 -0.12,-0.61l-2.03,-1.58zM12,15.5c-1.93,0 -3.5,-1.57 -3.5,-3.5s1.57,-3.5 3.5,-3.5 3.5,1.57 3.5,3.5 -1.57,3.5 -3.5,3.5z"/>
|
||||
</vector>
|
||||
|
||||
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<solid android:color="#4CAF50" />
|
||||
<corners android:radius="8dp" />
|
||||
</shape>
|
||||
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<solid android:color="@android:color/white" />
|
||||
<corners android:radius="16dp" />
|
||||
<stroke
|
||||
android:width="1dp"
|
||||
android:color="#E0E0E0" />
|
||||
</shape>
|
||||
@ -0,0 +1,73 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/background_secondary">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="12dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<EditText
|
||||
android:id="@+id/et_url"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:hint="输入教务系统网址"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_go"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="前往"
|
||||
android:textSize="14sp"
|
||||
android:backgroundTint="@color/button_secondary"
|
||||
android:textColor="@color/text_white"
|
||||
android:padding="8dp"/>
|
||||
</LinearLayout>
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progress_bar"
|
||||
style="@android:style/Widget.ProgressBar.Horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="3dp"
|
||||
android:max="100"
|
||||
android:progress="0"
|
||||
android:visibility="gone"/>
|
||||
|
||||
<WebView
|
||||
android:id="@+id/webview"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_start_import"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="我已在课表页,开始导入"
|
||||
android:textSize="16sp"
|
||||
android:backgroundTint="@color/button_primary"
|
||||
android:textColor="@color/text_white"
|
||||
android:padding="12dp"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_locate_timetable"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="自动定位课表"
|
||||
android:textSize="14sp"
|
||||
android:backgroundTint="@color/button_secondary"
|
||||
android:textColor="@color/text_white"
|
||||
android:padding="10dp"/>
|
||||
|
||||
<Space
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="8dp"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
@ -0,0 +1,283 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:background="@color/background_primary"
|
||||
android:padding="20dp">
|
||||
|
||||
<!-- 标题区域 -->
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="校园助手"
|
||||
android:textSize="28sp"
|
||||
android:textStyle="bold"
|
||||
android:textColor="@color/text_primary"
|
||||
android:gravity="start"
|
||||
android:layout_marginTop="24dp"
|
||||
android:layout_marginBottom="6dp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="一站式校园生活"
|
||||
android:textSize="14sp"
|
||||
android:textColor="@color/text_secondary"
|
||||
android:layout_marginBottom="18dp" />
|
||||
|
||||
<!-- 功能按钮网格 -->
|
||||
<GridLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"
|
||||
android:columnCount="2"
|
||||
android:rowCount="2"
|
||||
android:alignmentMode="alignMargins"
|
||||
android:columnOrderPreserved="false"
|
||||
android:useDefaultMargins="true">
|
||||
|
||||
<!-- 课表按钮 -->
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:id="@+id/card_timetable"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_row="0"
|
||||
android:layout_column="0"
|
||||
android:layout_rowWeight="1"
|
||||
android:layout_columnWeight="1"
|
||||
android:layout_margin="8dp"
|
||||
app:cardCornerRadius="16dp"
|
||||
app:cardElevation="2dp"
|
||||
app:strokeWidth="1dp"
|
||||
app:strokeColor="@color/border_light"
|
||||
android:clickable="true"
|
||||
android:foreground="?android:attr/selectableItemBackground">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:gravity="center"
|
||||
android:padding="18dp">
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="56dp"
|
||||
android:layout_height="56dp"
|
||||
android:background="@drawable/bg_circle"
|
||||
android:backgroundTint="@color/primary_bg">
|
||||
<ImageView
|
||||
android:layout_width="28dp"
|
||||
android:layout_height="28dp"
|
||||
android:layout_gravity="center"
|
||||
android:tint="@color/primary_dark"
|
||||
android:src="@android:drawable/ic_menu_month" />
|
||||
</FrameLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:gravity="center_horizontal"
|
||||
android:layout_marginTop="10dp">
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="课程表"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold"
|
||||
android:textColor="@color/text_primary" />
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="查看今日课程安排"
|
||||
android:textSize="13sp"
|
||||
android:textColor="@color/text_secondary" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
<!-- 笔记按钮 -->
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:id="@+id/card_notes"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_row="0"
|
||||
android:layout_column="1"
|
||||
android:layout_rowWeight="1"
|
||||
android:layout_columnWeight="1"
|
||||
android:layout_margin="8dp"
|
||||
app:cardCornerRadius="16dp"
|
||||
app:cardElevation="2dp"
|
||||
app:strokeWidth="1dp"
|
||||
app:strokeColor="@color/border_light"
|
||||
android:clickable="true"
|
||||
android:foreground="?android:attr/selectableItemBackground">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:gravity="center"
|
||||
android:padding="18dp">
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="56dp"
|
||||
android:layout_height="56dp"
|
||||
android:background="@drawable/bg_circle"
|
||||
android:backgroundTint="@color/accent_green_bg">
|
||||
<ImageView
|
||||
android:layout_width="26dp"
|
||||
android:layout_height="26dp"
|
||||
android:layout_gravity="center"
|
||||
android:tint="@color/accent_green_dark"
|
||||
android:src="@android:drawable/ic_menu_edit" />
|
||||
</FrameLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:gravity="center_horizontal"
|
||||
android:layout_marginTop="10dp">
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="课程笔记"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold"
|
||||
android:textColor="@color/text_primary" />
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="记录课堂灵感与作业"
|
||||
android:textSize="13sp"
|
||||
android:textColor="@color/text_secondary" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
<!-- 成绩按钮 -->
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:id="@+id/card_grades"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_row="1"
|
||||
android:layout_column="0"
|
||||
android:layout_rowWeight="1"
|
||||
android:layout_columnWeight="1"
|
||||
android:layout_margin="8dp"
|
||||
app:cardCornerRadius="16dp"
|
||||
app:cardElevation="2dp"
|
||||
app:strokeWidth="1dp"
|
||||
app:strokeColor="@color/border_light"
|
||||
android:clickable="true"
|
||||
android:foreground="?android:attr/selectableItemBackground">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:gravity="center"
|
||||
android:padding="18dp">
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="56dp"
|
||||
android:layout_height="56dp"
|
||||
android:background="@drawable/bg_circle"
|
||||
android:backgroundTint="@color/accent_orange_bg">
|
||||
<ImageView
|
||||
android:layout_width="28dp"
|
||||
android:layout_height="28dp"
|
||||
android:layout_gravity="center"
|
||||
android:tint="@color/accent_orange_dark"
|
||||
android:src="@android:drawable/ic_menu_sort_by_size" />
|
||||
</FrameLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:gravity="center_horizontal"
|
||||
android:layout_marginTop="10dp">
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="成绩查询"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold"
|
||||
android:textColor="@color/text_primary" />
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="导入并统计GPA"
|
||||
android:textSize="13sp"
|
||||
android:textColor="@color/text_secondary" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
<!-- 校园导航按钮 -->
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:id="@+id/card_campus"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_row="1"
|
||||
android:layout_column="1"
|
||||
android:layout_rowWeight="1"
|
||||
android:layout_columnWeight="1"
|
||||
android:layout_margin="8dp"
|
||||
app:cardCornerRadius="16dp"
|
||||
app:cardElevation="2dp"
|
||||
app:strokeWidth="1dp"
|
||||
app:strokeColor="@color/border_light"
|
||||
android:clickable="true"
|
||||
android:foreground="?android:attr/selectableItemBackground">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:gravity="center"
|
||||
android:padding="18dp">
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="56dp"
|
||||
android:layout_height="56dp"
|
||||
android:background="@drawable/bg_circle"
|
||||
android:backgroundTint="@color/accent_purple_bg">
|
||||
<ImageView
|
||||
android:layout_width="26dp"
|
||||
android:layout_height="26dp"
|
||||
android:layout_gravity="center"
|
||||
android:tint="@color/accent_purple_dark"
|
||||
android:src="@android:drawable/ic_menu_mylocation" />
|
||||
</FrameLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:gravity="center_horizontal"
|
||||
android:layout_marginTop="10dp">
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="校园导航"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold"
|
||||
android:textColor="@color/text_primary" />
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="找地点与路线指引"
|
||||
android:textSize="13sp"
|
||||
android:textColor="@color/text_secondary" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
</GridLayout>
|
||||
|
||||
</LinearLayout>
|
||||
@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/fragment_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
|
||||
@ -0,0 +1,129 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<!-- 顶部栏 -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical"
|
||||
android:layout_marginBottom="12dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/btn_close"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="←"
|
||||
android:textSize="22sp"
|
||||
android:padding="4dp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="编辑笔记"
|
||||
android:textStyle="bold"
|
||||
android:textSize="18sp"
|
||||
android:gravity="center" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<!-- 标题 -->
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="标题"
|
||||
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
|
||||
app:boxBackgroundMode="outline">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/et_title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:singleLine="true" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<!-- 关联课程 -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical"
|
||||
android:layout_marginTop="8dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="课程:"
|
||||
android:layout_marginEnd="8dp" />
|
||||
|
||||
<Spinner
|
||||
android:id="@+id/spinner_course"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1" />
|
||||
</LinearLayout>
|
||||
|
||||
<!-- 内容 - 使用WebView实现富文本编辑 -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical"
|
||||
android:layout_marginTop="8dp">
|
||||
|
||||
<WebView
|
||||
android:id="@+id/webview_content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1" />
|
||||
|
||||
<!-- 工具栏 -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:padding="8dp"
|
||||
android:background="@color/background_secondary">
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_insert_image"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="插入图片"
|
||||
android:textColor="@color/primary"
|
||||
app:strokeColor="@color/primary"
|
||||
style="@style/Widget.MaterialComponents.Button.OutlinedButton" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<!-- 操作按钮 -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="end"
|
||||
android:layout_marginTop="12dp">
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_cancel"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="取消" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_save"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="保存"
|
||||
android:layout_marginStart="12dp" />
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:background="?attr/colorPrimary"
|
||||
android:theme="@style/ThemeOverlay.AppCompat.Light"
|
||||
app:titleTextColor="@color/text_primary"
|
||||
app:subtitleTextColor="@color/text_secondary"
|
||||
app:navigationIconTint="@color/text_primary"
|
||||
app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />
|
||||
|
||||
<WebView
|
||||
android:id="@+id/webview"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
@ -0,0 +1,109 @@
|
||||
<?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">
|
||||
|
||||
<!-- 标题栏 -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:padding="16dp"
|
||||
android:backgroundTint="@color/primary">
|
||||
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="教务系统登录"
|
||||
android:textSize="18sp"
|
||||
android:textColor="@color/text_white"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_close"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="关闭"
|
||||
android:textColor="@color/text_white"
|
||||
android:background="@android:color/transparent" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<!-- WebView -->
|
||||
<WebView
|
||||
android:id="@+id/webview"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1" />
|
||||
|
||||
<!-- 解析状态显示 -->
|
||||
<LinearLayout
|
||||
android:id="@+id/layout_parsing_status"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="12dp"
|
||||
android:background="@color/primary_light"
|
||||
android:visibility="gone">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_parsing_status"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="正在解析数据..."
|
||||
android:textSize="14sp"
|
||||
android:textColor="@color/primary"
|
||||
android:gravity="center" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_parsing_count"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="已解析: 0 条数据"
|
||||
android:textSize="12sp"
|
||||
android:textColor="@color/text_secondary"
|
||||
android:gravity="center"
|
||||
android:layout_marginTop="4dp" />
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progress_parsing"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginTop="8dp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<!-- 底部操作栏 -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:padding="8dp"
|
||||
android:background="@color/background_secondary">
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_navigate_to_grades"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="跳转到学业页面"
|
||||
android:textSize="12sp"
|
||||
android:padding="8dp"
|
||||
android:layout_marginEnd="4dp" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_parse_data"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="解析当前页面"
|
||||
android:textSize="12sp"
|
||||
android:padding="8dp"
|
||||
android:layout_marginStart="4dp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
@ -0,0 +1,224 @@
|
||||
<?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:padding="24dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/add_course"
|
||||
android:textSize="24sp"
|
||||
android:textStyle="bold"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:gravity="center" />
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:hint="@string/course_name">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/et_course_name"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="text" />
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_error_course_name"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="@color/error"
|
||||
android:textSize="12sp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:visibility="gone" />
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:hint="@string/course_teacher">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/et_course_teacher"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="text" />
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_error_course_teacher"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="@color/error"
|
||||
android:textSize="12sp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:visibility="gone" />
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:hint="@string/course_location">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/et_course_location"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="text" />
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_error_course_location"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="@color/error"
|
||||
android:textSize="12sp"
|
||||
android:layout_marginBottom="12dp"
|
||||
android:visibility="gone" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/week_day"
|
||||
android:textSize="16sp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginBottom="8dp" />
|
||||
|
||||
<Spinner
|
||||
android:id="@+id/spinner_day_of_week"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="12dp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/course_time_slot"
|
||||
android:textSize="16sp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginBottom="8dp" />
|
||||
|
||||
<Spinner
|
||||
android:id="@+id/spinner_time_slot"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="12dp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="周次范围"
|
||||
android:textSize="16sp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginBottom="8dp" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:layout_marginBottom="12dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="第"
|
||||
android:textSize="16sp"
|
||||
android:gravity="center_vertical"
|
||||
android:layout_marginEnd="8dp" />
|
||||
|
||||
<Spinner
|
||||
android:id="@+id/spinner_start_week"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="周 至 第"
|
||||
android:textSize="16sp"
|
||||
android:gravity="center_vertical"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginEnd="8dp" />
|
||||
|
||||
<Spinner
|
||||
android:id="@+id/spinner_end_week"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="周"
|
||||
android:textSize="16sp"
|
||||
android:gravity="center_vertical"
|
||||
android:layout_marginStart="8dp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_reminder_settings"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="设置提醒"
|
||||
android:textSize="15sp"
|
||||
android:backgroundTint="@color/button_secondary"
|
||||
android:textColor="@color/text_white"
|
||||
android:padding="10dp"
|
||||
android:layout_marginBottom="16dp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_reminder_status"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="未设置提醒"
|
||||
android:textSize="14sp"
|
||||
android:textColor="@color/text_secondary"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:visibility="gone" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="end"
|
||||
android:layout_marginTop="16dp">
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_cancel"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/cancel"
|
||||
android:textSize="14sp"
|
||||
android:backgroundTint="@color/button_secondary"
|
||||
android:textColor="@color/text_white"
|
||||
android:padding="8dp"
|
||||
android:layout_marginEnd="8dp" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_save"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/save"
|
||||
android:textSize="14sp"
|
||||
android:backgroundTint="@color/button_primary"
|
||||
android:textColor="@color/text_white"
|
||||
android:padding="8dp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</ScrollView>
|
||||
@ -0,0 +1,132 @@
|
||||
<?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:padding="24dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_dialog_title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/add_grade"
|
||||
android:textSize="20sp"
|
||||
android:textStyle="bold"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:gravity="center" />
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="12dp"
|
||||
android:hint="@string/grade_subject">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/et_subject"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="text"
|
||||
android:maxLines="1" />
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:layout_marginBottom="12dp">
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:hint="@string/grade_score">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/et_score"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="numberDecimal"
|
||||
android:maxLines="1" />
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:layout_marginStart="8dp"
|
||||
android:hint="学分">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/et_credit"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="numberDecimal"
|
||||
android:maxLines="1" />
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="学期"
|
||||
android:textSize="16sp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginBottom="8dp" />
|
||||
|
||||
<Spinner
|
||||
android:id="@+id/spinner_semester"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="12dp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="考试类型"
|
||||
android:textSize="16sp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginBottom="8dp" />
|
||||
|
||||
<Spinner
|
||||
android:id="@+id/spinner_exam_type"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="end"
|
||||
android:layout_marginTop="16dp">
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_cancel"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/cancel"
|
||||
android:textSize="16sp"
|
||||
android:layout_marginEnd="8dp"
|
||||
style="@style/Widget.Material3.Button.OutlinedButton" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_save"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/save"
|
||||
android:textSize="16sp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</ScrollView>
|
||||
@ -0,0 +1,95 @@
|
||||
<?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:padding="24dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_dialog_title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/add_note"
|
||||
android:textSize="20sp"
|
||||
android:textStyle="bold"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:gravity="center" />
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="12dp"
|
||||
android:hint="@string/note_title">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/et_note_title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="text"
|
||||
android:maxLines="1" />
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/link_to_course"
|
||||
android:textSize="16sp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginBottom="8dp" />
|
||||
|
||||
<Spinner
|
||||
android:id="@+id/spinner_course"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="12dp" />
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:hint="@string/note_content">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/et_note_content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="textMultiLine"
|
||||
android:lines="6"
|
||||
android:gravity="top|start"
|
||||
android:scrollbars="vertical" />
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="end"
|
||||
android:layout_marginTop="16dp">
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_cancel"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/cancel"
|
||||
android:textSize="16sp"
|
||||
android:layout_marginEnd="8dp"
|
||||
style="@style/Widget.Material3.Button.OutlinedButton" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_save"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/save"
|
||||
android:textSize="16sp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</ScrollView>
|
||||
@ -0,0 +1,115 @@
|
||||
<?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="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="24dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="教务系统导入"
|
||||
android:textSize="24sp"
|
||||
android:textStyle="bold"
|
||||
android:gravity="center"
|
||||
android:layout_marginBottom="16dp" />
|
||||
|
||||
<!-- 学号输入 -->
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:hint="学号">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/et_student_id"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="number" />
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_error_student_id"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="@color/error"
|
||||
android:textSize="12sp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:visibility="gone" />
|
||||
|
||||
<!-- 姓名输入 -->
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:hint="姓名">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/et_student_name"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="textPersonName" />
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_error_student_name"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="@color/error"
|
||||
android:textSize="12sp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:visibility="gone" />
|
||||
|
||||
<!-- 验证码输入 -->
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:hint="验证码">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/et_verification_code"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="text" />
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_error_verification_code"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="@color/error"
|
||||
android:textSize="12sp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:visibility="gone" />
|
||||
|
||||
<!-- 按钮 -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="end">
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_cancel_import"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="取消"
|
||||
android:textSize="16sp"
|
||||
android:layout_marginEnd="8dp"
|
||||
style="@style/Widget.Material3.Button.OutlinedButton" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_confirm_import"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="确认导入"
|
||||
android:textSize="16sp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
@ -0,0 +1,129 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:paddingBottom="16dp"
|
||||
android:paddingTop="16dp">
|
||||
|
||||
<!-- 标题栏和筛选 -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical"
|
||||
android:layout_marginBottom="16dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/notes_title"
|
||||
android:textSize="24sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/fab_add_note"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@android:drawable/ic_input_add"
|
||||
android:backgroundTint="@color/primary"
|
||||
app:tint="@color/text_white"
|
||||
android:contentDescription="@string/add_note" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<!-- 课程筛选 -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical"
|
||||
android:layout_marginBottom="16dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="筛选课程:"
|
||||
android:textSize="16sp"
|
||||
android:layout_marginEnd="8dp" />
|
||||
|
||||
<Spinner
|
||||
android:id="@+id/spinner_course_filter"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<!-- 搜索笔记 -->
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/til_note_search"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="搜索笔记"
|
||||
app:startIconDrawable="@android:drawable/ic_menu_search"
|
||||
app:endIconMode="clear_text"
|
||||
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
|
||||
app:boxBackgroundMode="outline"
|
||||
app:boxCornerRadiusTopStart="12dp"
|
||||
app:boxCornerRadiusTopEnd="12dp"
|
||||
app:boxCornerRadiusBottomStart="12dp"
|
||||
app:boxCornerRadiusBottomEnd="12dp"
|
||||
android:layout_marginBottom="12dp">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/et_note_search"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:singleLine="true"
|
||||
android:maxLines="1"
|
||||
android:imeOptions="actionSearch" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<!-- 笔记列表 -->
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/rv_notes"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1" />
|
||||
|
||||
<!-- 空状态提示 -->
|
||||
<LinearLayout
|
||||
android:id="@+id/layout_empty"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical"
|
||||
android:gravity="center"
|
||||
android:visibility="gone">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="暂无笔记"
|
||||
android:textSize="18sp"
|
||||
android:textColor="@color/text_secondary" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="点击右上角 + 号添加笔记"
|
||||
android:textSize="14sp"
|
||||
android:textColor="@color/text_secondary"
|
||||
android:layout_marginTop="8dp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
|
||||
@ -0,0 +1,179 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp"
|
||||
android:background="@color/background_secondary">
|
||||
|
||||
<!-- 课表管理标题 -->
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/timetable_title"
|
||||
android:textSize="24sp"
|
||||
android:textStyle="bold"
|
||||
android:textColor="@color/text_primary"
|
||||
android:layout_marginBottom="8dp" />
|
||||
|
||||
<!-- 标题栏:三个操作按钮等宽、样式统一 -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical"
|
||||
android:layout_marginBottom="16dp">
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_import_courses"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/import_from_education"
|
||||
android:textSize="14sp"
|
||||
android:backgroundTint="@color/button_secondary"
|
||||
android:textColor="@color/text_white"
|
||||
android:padding="8dp"
|
||||
android:maxLines="1"
|
||||
android:ellipsize="end"
|
||||
android:layout_marginEnd="8dp" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_refresh"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="刷新"
|
||||
android:textSize="14sp"
|
||||
android:backgroundTint="@color/button_secondary"
|
||||
android:textColor="@color/text_white"
|
||||
android:padding="8dp"
|
||||
android:maxLines="1"
|
||||
android:ellipsize="end"
|
||||
android:layout_marginEnd="8dp" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_clear_all"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="清空"
|
||||
android:textSize="14sp"
|
||||
android:backgroundTint="@color/button_danger"
|
||||
android:textColor="@color/text_white"
|
||||
android:padding="8dp"
|
||||
android:maxLines="1"
|
||||
android:ellipsize="end"
|
||||
android:layout_marginEnd="8dp" />
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/fab_add_course"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@android:drawable/ic_menu_add"
|
||||
android:backgroundTint="@color/button_secondary"
|
||||
android:tint="@color/text_white"
|
||||
android:contentDescription="@string/add_course" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<!-- 周视图切换 -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center"
|
||||
android:layout_marginBottom="16dp">
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_prev_week"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/prev_week"
|
||||
android:textSize="14sp"
|
||||
android:backgroundTint="@color/button_secondary"
|
||||
android:textColor="@color/text_white"
|
||||
android:padding="8dp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_current_week"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/current_week"
|
||||
android:textAlignment="center"
|
||||
android:textSize="18sp"
|
||||
android:layout_margin="8dp" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_next_week"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/next_week"
|
||||
android:textSize="14sp"
|
||||
android:backgroundTint="@color/button_secondary"
|
||||
android:textColor="@color/text_white"
|
||||
android:padding="8dp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<!-- 课表容器(包含星期标题和课程内容,同步滚动) -->
|
||||
<HorizontalScrollView
|
||||
android:id="@+id/horizontal_scroll_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"
|
||||
android:fillViewport="true"
|
||||
android:scrollbars="none">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<!-- 周标题行(周一~周日) -->
|
||||
<LinearLayout
|
||||
android:id="@+id/layout_week_header"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="40dp"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical"
|
||||
android:layout_marginBottom="8dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_time_header"
|
||||
android:layout_width="56dp"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center"
|
||||
android:textStyle="bold"
|
||||
android:text="" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/week_days_container"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical" />
|
||||
</LinearLayout>
|
||||
|
||||
<!-- 课表网格与课程块 -->
|
||||
<ScrollView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:fillViewport="false"
|
||||
android:contentDescription="@string/timetable_scroll_description"
|
||||
tools:ignore="NestedScrolling">
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/timetable_container"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
</ScrollView>
|
||||
|
||||
</LinearLayout>
|
||||
</HorizontalScrollView>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
@ -0,0 +1,128 @@
|
||||
<?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="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="12dp"
|
||||
android:background="@color/background_card"
|
||||
android:layout_margin="4dp"
|
||||
android:elevation="2dp">
|
||||
|
||||
<!-- 课程名称作为主标题 -->
|
||||
<TextView
|
||||
android:id="@+id/tv_course_name"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="课程名称"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold"
|
||||
android:textColor="@color/text_primary"
|
||||
android:layout_marginBottom="8dp" />
|
||||
|
||||
<!-- 课程信息行 -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<!-- 课程编号 -->
|
||||
<TextView
|
||||
android:id="@+id/tv_course_code"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="编号: 课程编号"
|
||||
android:textSize="12sp"
|
||||
android:textColor="@color/text_secondary" />
|
||||
|
||||
<!-- 学分 -->
|
||||
<TextView
|
||||
android:id="@+id/tv_credit"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="学分: 学分"
|
||||
android:textSize="12sp"
|
||||
android:textColor="@color/text_secondary" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<!-- 成绩信息行 -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:layout_marginTop="4dp">
|
||||
|
||||
<!-- 成绩 -->
|
||||
<TextView
|
||||
android:id="@+id/tv_score"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="成绩: 94"
|
||||
android:textSize="14sp"
|
||||
android:textColor="@color/grade_good"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<!-- 成绩输入(当成绩为空时显示) -->
|
||||
<EditText
|
||||
android:id="@+id/et_score_input"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:inputType="number"
|
||||
android:hint="请输入成绩"
|
||||
android:maxLength="3"
|
||||
android:visibility="gone" />
|
||||
|
||||
<!-- 绩点 -->
|
||||
<TextView
|
||||
android:id="@+id/tv_gpa"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="绩点: 4.0"
|
||||
android:textSize="14sp"
|
||||
android:textColor="@color/grade_excellent"
|
||||
android:textStyle="bold" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<!-- 课程性质信息 -->
|
||||
<TextView
|
||||
android:id="@+id/tv_status"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="课程性质: 必修课"
|
||||
android:textSize="12sp"
|
||||
android:textColor="@color/text_secondary"
|
||||
android:layout_marginTop="4dp" />
|
||||
|
||||
<!-- 学年和学期信息 -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:layout_marginTop="4dp">
|
||||
|
||||
<!-- 学年 -->
|
||||
<TextView
|
||||
android:id="@+id/tv_year"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="学年: 2023-2024"
|
||||
android:textSize="12sp"
|
||||
android:textColor="@color/text_secondary" />
|
||||
|
||||
<!-- 学期 -->
|
||||
<TextView
|
||||
android:id="@+id/tv_term"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="学期: 1"
|
||||
android:textSize="12sp"
|
||||
android:textColor="@color/text_secondary" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
@ -0,0 +1,123 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<!-- 左滑操作按钮(置于背景层,垂直堆叠圆形按钮) -->
|
||||
<LinearLayout
|
||||
android:id="@+id/layout_swipe_actions"
|
||||
android:layout_width="96dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="end"
|
||||
android:orientation="vertical"
|
||||
android:gravity="center_vertical|end"
|
||||
android:background="@color/background_secondary"
|
||||
android:visibility="gone">
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/btn_edit"
|
||||
android:layout_width="56dp"
|
||||
android:layout_height="56dp"
|
||||
android:layout_marginBottom="12dp"
|
||||
android:src="@android:drawable/ic_menu_edit"
|
||||
android:tint="@color/text_white"
|
||||
android:background="@drawable/bg_circle_primary"
|
||||
android:backgroundTint="@null"
|
||||
android:contentDescription="编辑" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/btn_delete"
|
||||
android:layout_width="56dp"
|
||||
android:layout_height="56dp"
|
||||
android:src="@android:drawable/ic_menu_delete"
|
||||
android:tint="@color/text_white"
|
||||
android:background="@drawable/bg_circle_danger"
|
||||
android:backgroundTint="@null"
|
||||
android:contentDescription="删除" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<!-- 主内容(置于前景层) -->
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/card_content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="8dp"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
app:cardCornerRadius="8dp"
|
||||
app:cardElevation="4dp"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<LinearLayout
|
||||
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:gravity="center_vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_note_title"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="笔记标题"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold"
|
||||
android:maxLines="1"
|
||||
android:ellipsize="end" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_course_name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="高等数学"
|
||||
android:textSize="14sp"
|
||||
android:textColor="@color/text_white"
|
||||
android:background="@color/accent_green_light"
|
||||
android:paddingLeft="8dp"
|
||||
android:paddingRight="8dp"
|
||||
android:paddingTop="4dp"
|
||||
android:paddingBottom="4dp"
|
||||
android:layout_marginStart="8dp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_note_content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="笔记内容预览..."
|
||||
android:textSize="16sp"
|
||||
android:textColor="@color/text_secondary"
|
||||
android:layout_marginTop="8dp"
|
||||
android:maxLines="3"
|
||||
android:ellipsize="end" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="end"
|
||||
android:layout_marginTop="8dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_modify_time"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="修改时间"
|
||||
android:textSize="14sp"
|
||||
android:textColor="@color/text_secondary" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
</FrameLayout>
|
||||
@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item
|
||||
android:id="@+id/nav_timetable"
|
||||
android:title="课表"
|
||||
android:icon="@mipmap/ic_launcher" />
|
||||
<item
|
||||
android:id="@+id/nav_notes"
|
||||
android:title="笔记"
|
||||
android:icon="@mipmap/ic_launcher" />
|
||||
<item
|
||||
android:id="@+id/nav_grades"
|
||||
android:title="成绩"
|
||||
android:icon="@mipmap/ic_launcher" />
|
||||
<item
|
||||
android:id="@+id/nav_campus"
|
||||
android:title="导航"
|
||||
android:icon="@mipmap/ic_launcher" />
|
||||
</menu>
|
||||
|
||||
|
||||
@ -0,0 +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">
|
||||
<!-- 阅读界面不再提供编辑/删除按钮,菜单留空 -->
|
||||
</menu>
|
||||
|
||||
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@drawable/ic_launcher_background" />
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground" />
|
||||
</adaptive-icon>
|
||||
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@drawable/ic_launcher_background" />
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground" />
|
||||
</adaptive-icon>
|
||||
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@drawable/ic_launcher_background" />
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground" />
|
||||
<monochrome android:drawable="@drawable/ic_launcher_foreground" />
|
||||
</adaptive-icon>
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 982 B |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 3.8 KiB |
|
After Width: | Height: | Size: 2.8 KiB |