aia
Some checks failed
Flask 提示词大师 - CI/CD 流水线 / 代码质量检查 (push) Has been cancelled
Flask 提示词大师 - CI/CD 流水线 / 单元测试 (push) Has been cancelled
Flask 提示词大师 - CI/CD 流水线 / 集成测试 (push) Has been cancelled
Flask 提示词大师 - CI/CD 流水线 / 构建Docker镜像 (push) Has been cancelled
Flask 提示词大师 - CI/CD 流水线 / 部署到测试环境 (push) Has been cancelled
Flask 提示词大师 - CI/CD 流水线 / 部署到生产环境 (push) Has been cancelled
Flask 提示词大师 - CI/CD 流水线 / 部署监控系统 (push) Has been cancelled
Some checks failed
Flask 提示词大师 - CI/CD 流水线 / 代码质量检查 (push) Has been cancelled
Flask 提示词大师 - CI/CD 流水线 / 单元测试 (push) Has been cancelled
Flask 提示词大师 - CI/CD 流水线 / 集成测试 (push) Has been cancelled
Flask 提示词大师 - CI/CD 流水线 / 构建Docker镜像 (push) Has been cancelled
Flask 提示词大师 - CI/CD 流水线 / 部署到测试环境 (push) Has been cancelled
Flask 提示词大师 - CI/CD 流水线 / 部署到生产环境 (push) Has been cancelled
Flask 提示词大师 - CI/CD 流水线 / 部署监控系统 (push) Has been cancelled
This commit is contained in:
@@ -54,6 +54,26 @@
|
||||
android:name=".MeetingMinutesActivity"
|
||||
android:exported="false"
|
||||
android:screenOrientation="portrait" />
|
||||
<activity
|
||||
android:name=".TravelPlanningHistoryActivity"
|
||||
android:exported="false"
|
||||
android:screenOrientation="portrait" />
|
||||
<activity
|
||||
android:name=".WeeklyReportHistoryActivity"
|
||||
android:exported="false"
|
||||
android:screenOrientation="portrait" />
|
||||
<activity
|
||||
android:name=".MeetingMinutesHistoryActivity"
|
||||
android:exported="false"
|
||||
android:screenOrientation="portrait" />
|
||||
<activity
|
||||
android:name=".PoetryHistoryActivity"
|
||||
android:exported="false"
|
||||
android:screenOrientation="portrait" />
|
||||
<activity
|
||||
android:name=".ResumeOptimizationHistoryActivity"
|
||||
android:exported="false"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<provider
|
||||
android:name="androidx.core.content.FileProvider"
|
||||
|
||||
@@ -51,10 +51,9 @@ public class AIServicesActivity extends AppCompatActivity {
|
||||
entries.add(new AIServiceEntry("旅行攻略规划", "根据目的地与天数,AI 生成行程与实用建议", "出行", TravelPlanningActivity.class));
|
||||
entries.add(new AIServiceEntry("智能周报生成", "输入工作要点,一键生成规范周报/日报", "办公", WeeklyReportActivity.class));
|
||||
entries.add(new AIServiceEntry("会议纪要整理", "粘贴会议转写或要点,一键生成结构化会议纪要", "办公", MeetingMinutesActivity.class));
|
||||
// 占位:点击进入 PlaceholderActivity 显示「敬请期待」
|
||||
entries.add(new AIServiceEntry("古诗词解析", "深度解析古诗词意境,感受中华文化之美", "文化", null));
|
||||
entries.add(new AIServiceEntry("古诗词解析", "深度解析古诗词意境,感受中华文化之美", "文化", PoetryActivity.class));
|
||||
entries.add(new AIServiceEntry("古诗词收藏", "收藏喜爱的古诗词,建立个人文化宝库", "收藏", null));
|
||||
entries.add(new AIServiceEntry("简历/求职信优化", "润色简历或根据岗位生成针对性求职信", "求职", null));
|
||||
entries.add(new AIServiceEntry("简历/求职信优化", "润色简历或根据岗位生成针对性求职信", "求职", ResumeOptimizationActivity.class));
|
||||
entries.add(new AIServiceEntry("2号专家", "需求分析 + 领域专家生成高质量提示词", "专家", null));
|
||||
entries.add(new AIServiceEntry("3号专家", "需求分析 + 领域专家生成,含历史记录", "专家", null));
|
||||
entries.add(new AIServiceEntry("读书笔记", "生成摘要、金句、思维导图式大纲或读后感", "文化", null));
|
||||
|
||||
@@ -29,6 +29,9 @@ public class MeetingMinutesActivity extends AppCompatActivity {
|
||||
viewModel = new ViewModelProvider(this, new ViewModelProvider.AndroidViewModelFactory(getApplication())).get(MeetingMinutesViewModel.class);
|
||||
|
||||
binding.btnBack.setOnClickListener(v -> finish());
|
||||
if (binding.btnHistory != null) {
|
||||
binding.btnHistory.setOnClickListener(v -> startActivity(new android.content.Intent(this, MeetingMinutesHistoryActivity.class)));
|
||||
}
|
||||
binding.btnGenerate.setOnClickListener(v -> doGenerate());
|
||||
binding.btnCopy.setOnClickListener(v -> copyResult());
|
||||
observeViewModel();
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.ruilaizi.example;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.ruilaizi.example.adapter.MeetingMinutesHistoryAdapter;
|
||||
import com.ruilaizi.example.data.meeting.MeetingMinutesRepository;
|
||||
import com.ruilaizi.example.databinding.ActivityMeetingMinutesHistoryBinding;
|
||||
|
||||
public class MeetingMinutesHistoryActivity extends AppCompatActivity {
|
||||
|
||||
private ActivityMeetingMinutesHistoryBinding binding;
|
||||
private MeetingMinutesHistoryAdapter adapter;
|
||||
|
||||
@Override
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
binding = ActivityMeetingMinutesHistoryBinding.inflate(getLayoutInflater());
|
||||
setContentView(binding.getRoot());
|
||||
adapter = new MeetingMinutesHistoryAdapter();
|
||||
adapter.setOnUseListener(content -> {
|
||||
setResult(RESULT_OK);
|
||||
finish();
|
||||
});
|
||||
binding.recycler.setLayoutManager(new LinearLayoutManager(this));
|
||||
binding.recycler.setAdapter(adapter);
|
||||
binding.btnBack.setOnClickListener(v -> finish());
|
||||
MeetingMinutesRepository repo = new MeetingMinutesRepository(getApplication());
|
||||
repo.getRecentRecords().observe(this, list -> {
|
||||
adapter.setData(list);
|
||||
binding.emptyText.setVisibility(list == null || list.isEmpty() ? View.VISIBLE : View.GONE);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
package com.ruilaizi.example;
|
||||
|
||||
import android.content.ClipData;
|
||||
import android.content.ClipboardManager;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
|
||||
import com.google.android.material.snackbar.Snackbar;
|
||||
import com.google.android.material.textfield.TextInputEditText;
|
||||
import com.ruilaizi.example.databinding.ActivityPoetryBinding;
|
||||
import com.ruilaizi.example.ui.PoetryViewModel;
|
||||
|
||||
public class PoetryActivity extends AppCompatActivity {
|
||||
|
||||
private ActivityPoetryBinding binding;
|
||||
private PoetryViewModel viewModel;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
binding = ActivityPoetryBinding.inflate(getLayoutInflater());
|
||||
setContentView(binding.getRoot());
|
||||
viewModel = new ViewModelProvider(this, new ViewModelProvider.AndroidViewModelFactory(getApplication())).get(PoetryViewModel.class);
|
||||
|
||||
binding.btnBack.setOnClickListener(v -> finish());
|
||||
if (binding.btnHistory != null) {
|
||||
binding.btnHistory.setOnClickListener(v -> startActivity(new android.content.Intent(this, PoetryHistoryActivity.class)));
|
||||
}
|
||||
binding.btnGenerate.setOnClickListener(v -> doGenerate());
|
||||
binding.btnCopy.setOnClickListener(v -> copyResult());
|
||||
observeViewModel();
|
||||
}
|
||||
|
||||
private void doGenerate() {
|
||||
String title = getText(binding.etPoetryTitle);
|
||||
if (title.isEmpty()) {
|
||||
Toast.makeText(this, "请输入诗词标题", Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
viewModel.generate(title, getText(binding.etAuthor), getText(binding.etDynasty), getText(binding.etExtra));
|
||||
}
|
||||
|
||||
private String getText(TextInputEditText et) {
|
||||
return et.getText() != null ? et.getText().toString().trim() : "";
|
||||
}
|
||||
|
||||
private void copyResult() {
|
||||
String text = binding.tvResult.getText() != null ? binding.tvResult.getText().toString() : "";
|
||||
if (text.isEmpty()) {
|
||||
Snackbar.make(binding.getRoot(), "暂无内容可复制", Snackbar.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
ClipboardManager cm = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
if (cm != null) {
|
||||
cm.setPrimaryClip(ClipData.newPlainText("古诗词解析", text));
|
||||
Snackbar.make(binding.getRoot(), "已复制到剪贴板", Snackbar.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
|
||||
private void observeViewModel() {
|
||||
viewModel.getResultLiveData().observe(this, text -> {
|
||||
if (text != null) {
|
||||
binding.tvResult.setText(text);
|
||||
binding.tvResult.setTextColor(getResources().getColor(R.color.colorTextDark, getTheme()));
|
||||
}
|
||||
});
|
||||
viewModel.getLoadingLiveData().observe(this, loading -> {
|
||||
binding.progressBar.setVisibility(loading != null && loading ? View.VISIBLE : View.GONE);
|
||||
binding.btnGenerate.setEnabled(loading == null || !loading);
|
||||
});
|
||||
viewModel.getErrorLiveData().observe(this, error -> {
|
||||
if (error != null && !error.isEmpty()) {
|
||||
new AlertDialog.Builder(this).setMessage(error).setPositiveButton(android.R.string.ok, (d, w) -> viewModel.clearError()).show();
|
||||
}
|
||||
});
|
||||
viewModel.getSnackbarLiveData().observe(this, msg -> {
|
||||
if (msg != null && !msg.isEmpty()) {
|
||||
Snackbar.make(binding.getRoot(), msg, Snackbar.LENGTH_SHORT).show();
|
||||
viewModel.clearSnackbar();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.ruilaizi.example;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
|
||||
import com.ruilaizi.example.adapter.PoetryHistoryAdapter;
|
||||
import com.ruilaizi.example.data.poetry.PoetryRepository;
|
||||
import com.ruilaizi.example.databinding.ActivityPoetryHistoryBinding;
|
||||
|
||||
public class PoetryHistoryActivity extends AppCompatActivity {
|
||||
|
||||
private ActivityPoetryHistoryBinding binding;
|
||||
private PoetryHistoryAdapter adapter;
|
||||
|
||||
@Override
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
binding = ActivityPoetryHistoryBinding.inflate(getLayoutInflater());
|
||||
setContentView(binding.getRoot());
|
||||
adapter = new PoetryHistoryAdapter();
|
||||
adapter.setOnUseListener(content -> {
|
||||
setResult(RESULT_OK);
|
||||
finish();
|
||||
});
|
||||
binding.recycler.setLayoutManager(new LinearLayoutManager(this));
|
||||
binding.recycler.setAdapter(adapter);
|
||||
binding.btnBack.setOnClickListener(v -> finish());
|
||||
PoetryRepository repo = new PoetryRepository(getApplication());
|
||||
repo.getRecentRecords().observe(this, list -> {
|
||||
adapter.setData(list);
|
||||
binding.emptyText.setVisibility(list == null || list.isEmpty() ? View.VISIBLE : View.GONE);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
package com.ruilaizi.example;
|
||||
|
||||
import android.content.ClipData;
|
||||
import android.content.ClipboardManager;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
|
||||
import com.google.android.material.snackbar.Snackbar;
|
||||
import com.google.android.material.textfield.TextInputEditText;
|
||||
import com.ruilaizi.example.databinding.ActivityResumeOptimizationBinding;
|
||||
import com.ruilaizi.example.ui.ResumeOptimizationViewModel;
|
||||
|
||||
public class ResumeOptimizationActivity extends AppCompatActivity {
|
||||
|
||||
private ActivityResumeOptimizationBinding binding;
|
||||
private ResumeOptimizationViewModel viewModel;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
binding = ActivityResumeOptimizationBinding.inflate(getLayoutInflater());
|
||||
setContentView(binding.getRoot());
|
||||
viewModel = new ViewModelProvider(this, new ViewModelProvider.AndroidViewModelFactory(getApplication())).get(ResumeOptimizationViewModel.class);
|
||||
ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this, R.array.resume_opt_types, android.R.layout.simple_spinner_item);
|
||||
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
||||
binding.spinnerType.setAdapter(adapter);
|
||||
binding.btnBack.setOnClickListener(v -> finish());
|
||||
if (binding.btnHistory != null) {
|
||||
binding.btnHistory.setOnClickListener(v -> startActivity(new android.content.Intent(this, ResumeOptimizationHistoryActivity.class)));
|
||||
}
|
||||
binding.btnGenerate.setOnClickListener(v -> doGenerate());
|
||||
binding.btnCopy.setOnClickListener(v -> copyResult());
|
||||
observeViewModel();
|
||||
}
|
||||
|
||||
private void doGenerate() {
|
||||
String original = getText(binding.etOriginal);
|
||||
if (original.isEmpty()) {
|
||||
Toast.makeText(this, "请填写简历内容或求职信要点", Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
String optType = binding.spinnerType.getSelectedItemPosition() == 0 ? "resume" : "cover_letter";
|
||||
viewModel.generate(optType, original, getText(binding.etJobDesc));
|
||||
}
|
||||
|
||||
private String getText(TextInputEditText et) {
|
||||
return et.getText() != null ? et.getText().toString().trim() : "";
|
||||
}
|
||||
|
||||
private void copyResult() {
|
||||
String text = binding.tvResult.getText() != null ? binding.tvResult.getText().toString() : "";
|
||||
if (text.isEmpty()) {
|
||||
Snackbar.make(binding.getRoot(), "暂无内容可复制", Snackbar.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
ClipboardManager cm = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
if (cm != null) {
|
||||
cm.setPrimaryClip(ClipData.newPlainText("简历优化", text));
|
||||
Snackbar.make(binding.getRoot(), "已复制到剪贴板", Snackbar.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
|
||||
private void observeViewModel() {
|
||||
viewModel.getResultLiveData().observe(this, text -> {
|
||||
if (text != null) {
|
||||
binding.tvResult.setText(text);
|
||||
binding.tvResult.setTextColor(getResources().getColor(R.color.colorTextDark, getTheme()));
|
||||
}
|
||||
});
|
||||
viewModel.getLoadingLiveData().observe(this, loading -> {
|
||||
binding.progressBar.setVisibility(loading != null && loading ? View.VISIBLE : View.GONE);
|
||||
binding.btnGenerate.setEnabled(loading == null || !loading);
|
||||
});
|
||||
viewModel.getErrorLiveData().observe(this, error -> {
|
||||
if (error != null && !error.isEmpty()) {
|
||||
new AlertDialog.Builder(this).setMessage(error).setPositiveButton(android.R.string.ok, (d, w) -> viewModel.clearError()).show();
|
||||
}
|
||||
});
|
||||
viewModel.getSnackbarLiveData().observe(this, msg -> {
|
||||
if (msg != null && !msg.isEmpty()) {
|
||||
Snackbar.make(binding.getRoot(), msg, Snackbar.LENGTH_SHORT).show();
|
||||
viewModel.clearSnackbar();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.ruilaizi.example;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
|
||||
import com.ruilaizi.example.adapter.ResumeOptimizationHistoryAdapter;
|
||||
import com.ruilaizi.example.data.resume.ResumeOptimizationRepository;
|
||||
import com.ruilaizi.example.databinding.ActivityResumeOptimizationHistoryBinding;
|
||||
|
||||
public class ResumeOptimizationHistoryActivity extends AppCompatActivity {
|
||||
|
||||
private ActivityResumeOptimizationHistoryBinding binding;
|
||||
private ResumeOptimizationHistoryAdapter adapter;
|
||||
|
||||
@Override
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
binding = ActivityResumeOptimizationHistoryBinding.inflate(getLayoutInflater());
|
||||
setContentView(binding.getRoot());
|
||||
adapter = new ResumeOptimizationHistoryAdapter();
|
||||
adapter.setOnUseListener(content -> {
|
||||
setResult(RESULT_OK);
|
||||
finish();
|
||||
});
|
||||
binding.recycler.setLayoutManager(new LinearLayoutManager(this));
|
||||
binding.recycler.setAdapter(adapter);
|
||||
binding.btnBack.setOnClickListener(v -> finish());
|
||||
ResumeOptimizationRepository repo = new ResumeOptimizationRepository(getApplication());
|
||||
repo.getRecentRecords().observe(this, list -> {
|
||||
adapter.setData(list);
|
||||
binding.emptyText.setVisibility(list == null || list.isEmpty() ? View.VISIBLE : View.GONE);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,9 @@ public class TravelPlanningActivity extends AppCompatActivity {
|
||||
setContentView(binding.getRoot());
|
||||
viewModel = new ViewModelProvider(this, new ViewModelProvider.AndroidViewModelFactory(getApplication())).get(TravelPlanningViewModel.class);
|
||||
binding.btnBack.setOnClickListener(v -> finish());
|
||||
if (binding.btnHistory != null) {
|
||||
binding.btnHistory.setOnClickListener(v -> startActivity(new android.content.Intent(this, TravelPlanningHistoryActivity.class)));
|
||||
}
|
||||
binding.btnGenerate.setOnClickListener(v -> doGenerate());
|
||||
binding.btnCopy.setOnClickListener(v -> copyResult());
|
||||
observeViewModel();
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.ruilaizi.example;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.ruilaizi.example.adapter.TravelHistoryAdapter;
|
||||
import com.ruilaizi.example.data.travel.TravelPlanningRepository;
|
||||
import com.ruilaizi.example.databinding.ActivityTravelPlanningHistoryBinding;
|
||||
|
||||
public class TravelPlanningHistoryActivity extends AppCompatActivity {
|
||||
|
||||
private ActivityTravelPlanningHistoryBinding binding;
|
||||
private TravelHistoryAdapter adapter;
|
||||
|
||||
@Override
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
binding = ActivityTravelPlanningHistoryBinding.inflate(getLayoutInflater());
|
||||
setContentView(binding.getRoot());
|
||||
adapter = new TravelHistoryAdapter();
|
||||
adapter.setOnUseListener(content -> {
|
||||
setResult(RESULT_OK);
|
||||
finish();
|
||||
});
|
||||
binding.recycler.setLayoutManager(new LinearLayoutManager(this));
|
||||
binding.recycler.setAdapter(adapter);
|
||||
binding.btnBack.setOnClickListener(v -> finish());
|
||||
TravelPlanningRepository repo = new TravelPlanningRepository(getApplication());
|
||||
repo.getRecentRecords().observe(this, list -> {
|
||||
adapter.setData(list);
|
||||
binding.emptyText.setVisibility(list == null || list.isEmpty() ? View.VISIBLE : View.GONE);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -29,6 +29,9 @@ public class WeeklyReportActivity extends AppCompatActivity {
|
||||
viewModel = new ViewModelProvider(this, new ViewModelProvider.AndroidViewModelFactory(getApplication())).get(WeeklyReportViewModel.class);
|
||||
|
||||
binding.btnBack.setOnClickListener(v -> finish());
|
||||
if (binding.btnHistory != null) {
|
||||
binding.btnHistory.setOnClickListener(v -> startActivity(new android.content.Intent(this, WeeklyReportHistoryActivity.class)));
|
||||
}
|
||||
binding.btnGenerate.setOnClickListener(v -> doGenerate());
|
||||
binding.btnCopy.setOnClickListener(v -> copyResult());
|
||||
observeViewModel();
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.ruilaizi.example;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.ruilaizi.example.adapter.WeeklyReportHistoryAdapter;
|
||||
import com.ruilaizi.example.data.weekly.WeeklyReportRepository;
|
||||
import com.ruilaizi.example.databinding.ActivityWeeklyReportHistoryBinding;
|
||||
|
||||
public class WeeklyReportHistoryActivity extends AppCompatActivity {
|
||||
|
||||
private ActivityWeeklyReportHistoryBinding binding;
|
||||
private WeeklyReportHistoryAdapter adapter;
|
||||
|
||||
@Override
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
binding = ActivityWeeklyReportHistoryBinding.inflate(getLayoutInflater());
|
||||
setContentView(binding.getRoot());
|
||||
adapter = new WeeklyReportHistoryAdapter();
|
||||
adapter.setOnUseListener(content -> {
|
||||
setResult(RESULT_OK);
|
||||
finish();
|
||||
});
|
||||
binding.recycler.setLayoutManager(new LinearLayoutManager(this));
|
||||
binding.recycler.setAdapter(adapter);
|
||||
binding.btnBack.setOnClickListener(v -> finish());
|
||||
WeeklyReportRepository repo = new WeeklyReportRepository(getApplication());
|
||||
repo.getRecentRecords().observe(this, list -> {
|
||||
adapter.setData(list);
|
||||
binding.emptyText.setVisibility(list == null || list.isEmpty() ? View.VISIBLE : View.GONE);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
package com.ruilaizi.example.adapter;
|
||||
|
||||
import android.content.ClipData;
|
||||
import android.content.ClipboardManager;
|
||||
import android.content.Context;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.google.android.material.button.MaterialButton;
|
||||
import com.ruilaizi.example.R;
|
||||
import com.ruilaizi.example.data.db.MeetingMinutesRecord;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
public class MeetingMinutesHistoryAdapter extends RecyclerView.Adapter<MeetingMinutesHistoryAdapter.ViewHolder> {
|
||||
|
||||
private final List<MeetingMinutesRecord> list = new ArrayList<>();
|
||||
private OnUseListener onUseListener;
|
||||
|
||||
public interface OnUseListener {
|
||||
void onUse(String summaryContent);
|
||||
}
|
||||
|
||||
public void setOnUseListener(OnUseListener listener) {
|
||||
this.onUseListener = listener;
|
||||
}
|
||||
|
||||
public void setData(List<MeetingMinutesRecord> data) {
|
||||
list.clear();
|
||||
if (data != null) list.addAll(data);
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_meeting_minutes_history, parent, false);
|
||||
return new ViewHolder(v);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
|
||||
MeetingMinutesRecord r = list.get(position);
|
||||
holder.tvSummary.setText(r.title != null && !r.title.isEmpty() ? r.title : "会议纪要");
|
||||
holder.tvContentPreview.setText(truncate(r.summaryContent, 80));
|
||||
holder.tvTime.setText(formatTime(r.createdAt));
|
||||
holder.btnUse.setOnClickListener(v -> {
|
||||
if (onUseListener != null && r.summaryContent != null) onUseListener.onUse(r.summaryContent);
|
||||
});
|
||||
holder.btnCopy.setOnClickListener(v -> {
|
||||
if (r.summaryContent != null && !r.summaryContent.isEmpty()) {
|
||||
ClipboardManager cm = (ClipboardManager) holder.itemView.getContext().getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
if (cm != null) cm.setPrimaryClip(ClipData.newPlainText("会议纪要", r.summaryContent));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return list.size();
|
||||
}
|
||||
|
||||
private static String truncate(String s, int maxLen) {
|
||||
if (s == null) return "";
|
||||
s = s.trim();
|
||||
return s.length() <= maxLen ? s : s.substring(0, maxLen) + "…";
|
||||
}
|
||||
private static String formatTime(long timestamp) {
|
||||
try {
|
||||
return new SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.getDefault()).format(new Date(timestamp));
|
||||
} catch (Exception e) { return ""; }
|
||||
}
|
||||
|
||||
static class ViewHolder extends RecyclerView.ViewHolder {
|
||||
TextView tvSummary, tvContentPreview, tvTime;
|
||||
MaterialButton btnUse, btnCopy;
|
||||
ViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
tvSummary = itemView.findViewById(R.id.tv_summary);
|
||||
tvContentPreview = itemView.findViewById(R.id.tv_content_preview);
|
||||
tvTime = itemView.findViewById(R.id.tv_time);
|
||||
btnUse = itemView.findViewById(R.id.btn_use);
|
||||
btnCopy = itemView.findViewById(R.id.btn_copy);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
package com.ruilaizi.example.adapter;
|
||||
|
||||
import android.content.ClipData;
|
||||
import android.content.ClipboardManager;
|
||||
import android.content.Context;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.google.android.material.button.MaterialButton;
|
||||
import com.ruilaizi.example.R;
|
||||
import com.ruilaizi.example.data.db.PoetryRecord;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
public class PoetryHistoryAdapter extends RecyclerView.Adapter<PoetryHistoryAdapter.ViewHolder> {
|
||||
|
||||
private final List<PoetryRecord> list = new ArrayList<>();
|
||||
private OnUseListener onUseListener;
|
||||
|
||||
public interface OnUseListener {
|
||||
void onUse(String summaryContent);
|
||||
}
|
||||
|
||||
public void setOnUseListener(OnUseListener listener) {
|
||||
this.onUseListener = listener;
|
||||
}
|
||||
|
||||
public void setData(List<PoetryRecord> data) {
|
||||
list.clear();
|
||||
if (data != null) list.addAll(data);
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_poetry_history, parent, false);
|
||||
return new ViewHolder(v);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
|
||||
PoetryRecord r = list.get(position);
|
||||
holder.tvSummary.setText(r.poetryTitle != null ? r.poetryTitle : "古诗词");
|
||||
holder.tvContentPreview.setText(truncate(r.analysisContent, 80));
|
||||
holder.tvTime.setText(formatTime(r.createdAt));
|
||||
holder.btnUse.setOnClickListener(v -> {
|
||||
if (onUseListener != null && r.analysisContent != null) onUseListener.onUse(r.analysisContent);
|
||||
});
|
||||
holder.btnCopy.setOnClickListener(v -> {
|
||||
if (r.analysisContent != null && !r.analysisContent.isEmpty()) {
|
||||
ClipboardManager cm = (ClipboardManager) holder.itemView.getContext().getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
if (cm != null) cm.setPrimaryClip(ClipData.newPlainText("古诗词解析", r.analysisContent));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return list.size();
|
||||
}
|
||||
|
||||
private static String truncate(String s, int maxLen) {
|
||||
if (s == null) return "";
|
||||
s = s.trim();
|
||||
return s.length() <= maxLen ? s : s.substring(0, maxLen) + "…";
|
||||
}
|
||||
private static String formatTime(long timestamp) {
|
||||
try {
|
||||
return new SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.getDefault()).format(new Date(timestamp));
|
||||
} catch (Exception e) { return ""; }
|
||||
}
|
||||
|
||||
static class ViewHolder extends RecyclerView.ViewHolder {
|
||||
TextView tvSummary, tvContentPreview, tvTime;
|
||||
MaterialButton btnUse, btnCopy;
|
||||
ViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
tvSummary = itemView.findViewById(R.id.tv_summary);
|
||||
tvContentPreview = itemView.findViewById(R.id.tv_content_preview);
|
||||
tvTime = itemView.findViewById(R.id.tv_time);
|
||||
btnUse = itemView.findViewById(R.id.btn_use);
|
||||
btnCopy = itemView.findViewById(R.id.btn_copy);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
package com.ruilaizi.example.adapter;
|
||||
|
||||
import android.content.ClipData;
|
||||
import android.content.ClipboardManager;
|
||||
import android.content.Context;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.google.android.material.button.MaterialButton;
|
||||
import com.ruilaizi.example.R;
|
||||
import com.ruilaizi.example.data.db.ResumeOptimizationRecord;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
public class ResumeOptimizationHistoryAdapter extends RecyclerView.Adapter<ResumeOptimizationHistoryAdapter.ViewHolder> {
|
||||
|
||||
private final List<ResumeOptimizationRecord> list = new ArrayList<>();
|
||||
private OnUseListener onUseListener;
|
||||
|
||||
public interface OnUseListener {
|
||||
void onUse(String summaryContent);
|
||||
}
|
||||
|
||||
public void setOnUseListener(OnUseListener listener) {
|
||||
this.onUseListener = listener;
|
||||
}
|
||||
|
||||
public void setData(List<ResumeOptimizationRecord> data) {
|
||||
list.clear();
|
||||
if (data != null) list.addAll(data);
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_resume_history, parent, false);
|
||||
return new ViewHolder(v);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
|
||||
ResumeOptimizationRecord r = list.get(position);
|
||||
holder.tvSummary.setText("cover_letter".equals(r.optType) ? "求职信" : "简历优化");
|
||||
holder.tvContentPreview.setText(truncate(r.optimizedContent, 80));
|
||||
holder.tvTime.setText(formatTime(r.createdAt));
|
||||
holder.btnUse.setOnClickListener(v -> {
|
||||
if (onUseListener != null && r.optimizedContent != null) onUseListener.onUse(r.optimizedContent);
|
||||
});
|
||||
holder.btnCopy.setOnClickListener(v -> {
|
||||
if (r.optimizedContent != null && !r.optimizedContent.isEmpty()) {
|
||||
ClipboardManager cm = (ClipboardManager) holder.itemView.getContext().getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
if (cm != null) cm.setPrimaryClip(ClipData.newPlainText("简历优化", r.optimizedContent));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return list.size();
|
||||
}
|
||||
|
||||
private static String truncate(String s, int maxLen) {
|
||||
if (s == null) return "";
|
||||
s = s.trim();
|
||||
return s.length() <= maxLen ? s : s.substring(0, maxLen) + "…";
|
||||
}
|
||||
private static String formatTime(long timestamp) {
|
||||
try {
|
||||
return new SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.getDefault()).format(new Date(timestamp));
|
||||
} catch (Exception e) { return ""; }
|
||||
}
|
||||
|
||||
static class ViewHolder extends RecyclerView.ViewHolder {
|
||||
TextView tvSummary, tvContentPreview, tvTime;
|
||||
MaterialButton btnUse, btnCopy;
|
||||
ViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
tvSummary = itemView.findViewById(R.id.tv_summary);
|
||||
tvContentPreview = itemView.findViewById(R.id.tv_content_preview);
|
||||
tvTime = itemView.findViewById(R.id.tv_time);
|
||||
btnUse = itemView.findViewById(R.id.btn_use);
|
||||
btnCopy = itemView.findViewById(R.id.btn_copy);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
package com.ruilaizi.example.adapter;
|
||||
|
||||
import android.content.ClipData;
|
||||
import android.content.ClipboardManager;
|
||||
import android.content.Context;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.google.android.material.button.MaterialButton;
|
||||
import com.ruilaizi.example.R;
|
||||
import com.ruilaizi.example.data.db.TravelPlanRecord;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
public class TravelHistoryAdapter extends RecyclerView.Adapter<TravelHistoryAdapter.ViewHolder> {
|
||||
|
||||
private final List<TravelPlanRecord> list = new ArrayList<>();
|
||||
private OnUseListener onUseListener;
|
||||
|
||||
public interface OnUseListener {
|
||||
void onUse(String planContent);
|
||||
}
|
||||
|
||||
public void setOnUseListener(OnUseListener listener) {
|
||||
this.onUseListener = listener;
|
||||
}
|
||||
|
||||
public void setData(List<TravelPlanRecord> data) {
|
||||
list.clear();
|
||||
if (data != null) {
|
||||
list.addAll(data);
|
||||
}
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_travel_history, parent, false);
|
||||
return new ViewHolder(v);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
|
||||
TravelPlanRecord r = list.get(position);
|
||||
String summary = safe(r.destination) + " | " + safe(r.days) + "天 | " + safe(r.people) + "人";
|
||||
holder.tvSummary.setText(summary);
|
||||
holder.tvContentPreview.setText(truncate(r.planContent, 80));
|
||||
holder.tvTime.setText(formatTime(r.createdAt));
|
||||
holder.btnUse.setOnClickListener(v -> {
|
||||
if (onUseListener != null && r.planContent != null) onUseListener.onUse(r.planContent);
|
||||
});
|
||||
holder.btnCopy.setOnClickListener(v -> {
|
||||
if (r.planContent != null && !r.planContent.isEmpty()) {
|
||||
ClipboardManager cm = (ClipboardManager) holder.itemView.getContext().getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
if (cm != null) cm.setPrimaryClip(ClipData.newPlainText("旅行攻略", r.planContent));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return list.size();
|
||||
}
|
||||
|
||||
private static String safe(String s) {
|
||||
return s != null ? s : "";
|
||||
}
|
||||
|
||||
private static String truncate(String s, int maxLen) {
|
||||
if (s == null) return "";
|
||||
s = s.trim();
|
||||
if (s.length() <= maxLen) return s;
|
||||
return s.substring(0, maxLen) + "…";
|
||||
}
|
||||
|
||||
private static String formatTime(long timestamp) {
|
||||
try {
|
||||
return new SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.getDefault()).format(new Date(timestamp));
|
||||
} catch (Exception e) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
static class ViewHolder extends RecyclerView.ViewHolder {
|
||||
TextView tvSummary, tvContentPreview, tvTime;
|
||||
MaterialButton btnUse, btnCopy;
|
||||
|
||||
ViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
tvSummary = itemView.findViewById(R.id.tv_summary);
|
||||
tvContentPreview = itemView.findViewById(R.id.tv_content_preview);
|
||||
tvTime = itemView.findViewById(R.id.tv_time);
|
||||
btnUse = itemView.findViewById(R.id.btn_use);
|
||||
btnCopy = itemView.findViewById(R.id.btn_copy);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
package com.ruilaizi.example.adapter;
|
||||
|
||||
import android.content.ClipData;
|
||||
import android.content.ClipboardManager;
|
||||
import android.content.Context;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.google.android.material.button.MaterialButton;
|
||||
import com.ruilaizi.example.R;
|
||||
import com.ruilaizi.example.data.db.WeeklyReportRecord;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
public class WeeklyReportHistoryAdapter extends RecyclerView.Adapter<WeeklyReportHistoryAdapter.ViewHolder> {
|
||||
|
||||
private final List<WeeklyReportRecord> list = new ArrayList<>();
|
||||
private OnUseListener onUseListener;
|
||||
|
||||
public interface OnUseListener {
|
||||
void onUse(String reportContent);
|
||||
}
|
||||
|
||||
public void setOnUseListener(OnUseListener listener) {
|
||||
this.onUseListener = listener;
|
||||
}
|
||||
|
||||
public void setData(List<WeeklyReportRecord> data) {
|
||||
list.clear();
|
||||
if (data != null) {
|
||||
list.addAll(data);
|
||||
}
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_weekly_report_history, parent, false);
|
||||
return new ViewHolder(v);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
|
||||
WeeklyReportRecord r = list.get(position);
|
||||
String summary = "weekly".equals(r.reportType) ? "周报" : "日报";
|
||||
holder.tvSummary.setText(summary);
|
||||
holder.tvContentPreview.setText(truncate(r.reportContent, 80));
|
||||
holder.tvTime.setText(formatTime(r.createdAt));
|
||||
holder.btnUse.setOnClickListener(v -> {
|
||||
if (onUseListener != null && r.reportContent != null) onUseListener.onUse(r.reportContent);
|
||||
});
|
||||
holder.btnCopy.setOnClickListener(v -> {
|
||||
if (r.reportContent != null && !r.reportContent.isEmpty()) {
|
||||
ClipboardManager cm = (ClipboardManager) holder.itemView.getContext().getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
if (cm != null) cm.setPrimaryClip(ClipData.newPlainText("周报", r.reportContent));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return list.size();
|
||||
}
|
||||
|
||||
private static String safe(String s) {
|
||||
return s != null ? s : "";
|
||||
}
|
||||
|
||||
private static String truncate(String s, int maxLen) {
|
||||
if (s == null) return "";
|
||||
s = s.trim();
|
||||
if (s.length() <= maxLen) return s;
|
||||
return s.substring(0, maxLen) + "…";
|
||||
}
|
||||
|
||||
private static String formatTime(long timestamp) {
|
||||
try {
|
||||
return new SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.getDefault()).format(new Date(timestamp));
|
||||
} catch (Exception e) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
static class ViewHolder extends RecyclerView.ViewHolder {
|
||||
TextView tvSummary, tvContentPreview, tvTime;
|
||||
MaterialButton btnUse, btnCopy;
|
||||
|
||||
ViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
tvSummary = itemView.findViewById(R.id.tv_summary);
|
||||
tvContentPreview = itemView.findViewById(R.id.tv_content_preview);
|
||||
tvTime = itemView.findViewById(R.id.tv_time);
|
||||
btnUse = itemView.findViewById(R.id.btn_use);
|
||||
btnCopy = itemView.findViewById(R.id.btn_copy);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,9 @@ import androidx.room.Database;
|
||||
import androidx.room.Room;
|
||||
import androidx.room.RoomDatabase;
|
||||
|
||||
@Database(entities = {GenerationRecord.class, OptimizeRecord.class, DirectAnswerRecord.class, MealPlanRecord.class}, version = 4, exportSchema = false)
|
||||
@Database(entities = {GenerationRecord.class, OptimizeRecord.class, DirectAnswerRecord.class, MealPlanRecord.class,
|
||||
TravelPlanRecord.class, WeeklyReportRecord.class, MeetingMinutesRecord.class,
|
||||
PoetryRecord.class, ResumeOptimizationRecord.class}, version = 6, exportSchema = false)
|
||||
public abstract class AppDatabase extends RoomDatabase {
|
||||
|
||||
private static volatile AppDatabase INSTANCE;
|
||||
@@ -30,4 +32,9 @@ public abstract class AppDatabase extends RoomDatabase {
|
||||
public abstract OptimizeRecordDao optimizeRecordDao();
|
||||
public abstract DirectAnswerRecordDao directAnswerRecordDao();
|
||||
public abstract MealPlanRecordDao mealPlanRecordDao();
|
||||
public abstract TravelPlanRecordDao travelPlanRecordDao();
|
||||
public abstract WeeklyReportRecordDao weeklyReportRecordDao();
|
||||
public abstract MeetingMinutesRecordDao meetingMinutesRecordDao();
|
||||
public abstract PoetryRecordDao poetryRecordDao();
|
||||
public abstract ResumeOptimizationRecordDao resumeOptimizationRecordDao();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.ruilaizi.example.data.db;
|
||||
|
||||
import androidx.room.Entity;
|
||||
import androidx.room.PrimaryKey;
|
||||
|
||||
/** 会议纪要历史记录 */
|
||||
@Entity(tableName = "meeting_minutes_records")
|
||||
public class MeetingMinutesRecord {
|
||||
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
public long id;
|
||||
public String title;
|
||||
public String rawContent;
|
||||
public String summaryContent;
|
||||
public long createdAt;
|
||||
|
||||
public MeetingMinutesRecord() {}
|
||||
|
||||
public MeetingMinutesRecord(String title, String rawContent, String summaryContent) {
|
||||
this.title = title;
|
||||
this.rawContent = rawContent;
|
||||
this.summaryContent = summaryContent;
|
||||
this.createdAt = System.currentTimeMillis();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.ruilaizi.example.data.db;
|
||||
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.room.Dao;
|
||||
import androidx.room.Insert;
|
||||
import androidx.room.Query;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Dao
|
||||
public interface MeetingMinutesRecordDao {
|
||||
|
||||
@Insert
|
||||
long insert(MeetingMinutesRecord record);
|
||||
|
||||
@Query("SELECT * FROM meeting_minutes_records ORDER BY createdAt DESC LIMIT 50")
|
||||
LiveData<List<MeetingMinutesRecord>> getRecentRecords();
|
||||
|
||||
@Query("DELETE FROM meeting_minutes_records WHERE id NOT IN (SELECT id FROM meeting_minutes_records ORDER BY createdAt DESC LIMIT 50)")
|
||||
void keepOnlyRecent();
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.ruilaizi.example.data.db;
|
||||
|
||||
import androidx.room.Entity;
|
||||
import androidx.room.PrimaryKey;
|
||||
|
||||
@Entity(tableName = "poetry_records")
|
||||
public class PoetryRecord {
|
||||
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
public long id;
|
||||
public String poetryTitle;
|
||||
public String author;
|
||||
public String dynasty;
|
||||
public String analysisContent;
|
||||
public long createdAt;
|
||||
|
||||
public PoetryRecord() {}
|
||||
|
||||
public PoetryRecord(String poetryTitle, String author, String dynasty, String analysisContent) {
|
||||
this.poetryTitle = poetryTitle;
|
||||
this.author = author;
|
||||
this.dynasty = dynasty;
|
||||
this.analysisContent = analysisContent;
|
||||
this.createdAt = System.currentTimeMillis();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.ruilaizi.example.data.db;
|
||||
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.room.Dao;
|
||||
import androidx.room.Insert;
|
||||
import androidx.room.Query;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Dao
|
||||
public interface PoetryRecordDao {
|
||||
|
||||
@Insert
|
||||
long insert(PoetryRecord record);
|
||||
|
||||
@Query("SELECT * FROM poetry_records ORDER BY createdAt DESC LIMIT 50")
|
||||
LiveData<List<PoetryRecord>> getRecentRecords();
|
||||
|
||||
@Query("DELETE FROM poetry_records WHERE id NOT IN (SELECT id FROM poetry_records ORDER BY createdAt DESC LIMIT 50)")
|
||||
void keepOnlyRecent();
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.ruilaizi.example.data.db;
|
||||
|
||||
import androidx.room.Entity;
|
||||
import androidx.room.PrimaryKey;
|
||||
|
||||
/** 简历/求职信优化历史记录 */
|
||||
@Entity(tableName = "resume_optimization_records")
|
||||
public class ResumeOptimizationRecord {
|
||||
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
public long id;
|
||||
public String optType; // resume | cover_letter
|
||||
public String originalContent;
|
||||
public String jobDescription;
|
||||
public String optimizedContent;
|
||||
public long createdAt;
|
||||
|
||||
public ResumeOptimizationRecord() {}
|
||||
|
||||
public ResumeOptimizationRecord(String optType, String originalContent, String jobDescription, String optimizedContent) {
|
||||
this.optType = optType;
|
||||
this.originalContent = originalContent;
|
||||
this.jobDescription = jobDescription;
|
||||
this.optimizedContent = optimizedContent;
|
||||
this.createdAt = System.currentTimeMillis();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.ruilaizi.example.data.db;
|
||||
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.room.Dao;
|
||||
import androidx.room.Insert;
|
||||
import androidx.room.Query;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Dao
|
||||
public interface ResumeOptimizationRecordDao {
|
||||
|
||||
@Insert
|
||||
long insert(ResumeOptimizationRecord record);
|
||||
|
||||
@Query("SELECT * FROM resume_optimization_records ORDER BY createdAt DESC LIMIT 50")
|
||||
LiveData<List<ResumeOptimizationRecord>> getRecentRecords();
|
||||
|
||||
@Query("DELETE FROM resume_optimization_records WHERE id NOT IN (SELECT id FROM resume_optimization_records ORDER BY createdAt DESC LIMIT 50)")
|
||||
void keepOnlyRecent();
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.ruilaizi.example.data.db;
|
||||
|
||||
import androidx.room.Entity;
|
||||
import androidx.room.PrimaryKey;
|
||||
|
||||
/** 旅行攻略历史记录 */
|
||||
@Entity(tableName = "travel_plan_records")
|
||||
public class TravelPlanRecord {
|
||||
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
public long id;
|
||||
public String destination;
|
||||
public String days;
|
||||
public String people;
|
||||
public String preferences;
|
||||
public String budget;
|
||||
public String planContent;
|
||||
public long createdAt;
|
||||
|
||||
public TravelPlanRecord() {}
|
||||
|
||||
public TravelPlanRecord(String destination, String days, String people, String preferences, String budget, String planContent) {
|
||||
this.destination = destination;
|
||||
this.days = days;
|
||||
this.people = people;
|
||||
this.preferences = preferences;
|
||||
this.budget = budget;
|
||||
this.planContent = planContent;
|
||||
this.createdAt = System.currentTimeMillis();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.ruilaizi.example.data.db;
|
||||
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.room.Dao;
|
||||
import androidx.room.Insert;
|
||||
import androidx.room.Query;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Dao
|
||||
public interface TravelPlanRecordDao {
|
||||
|
||||
@Insert
|
||||
long insert(TravelPlanRecord record);
|
||||
|
||||
@Query("SELECT * FROM travel_plan_records ORDER BY createdAt DESC LIMIT 50")
|
||||
LiveData<List<TravelPlanRecord>> getRecentRecords();
|
||||
|
||||
@Query("DELETE FROM travel_plan_records WHERE id NOT IN (SELECT id FROM travel_plan_records ORDER BY createdAt DESC LIMIT 50)")
|
||||
void keepOnlyRecent();
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.ruilaizi.example.data.db;
|
||||
|
||||
import androidx.room.Entity;
|
||||
import androidx.room.PrimaryKey;
|
||||
|
||||
/** 周报/日报历史记录 */
|
||||
@Entity(tableName = "weekly_report_records")
|
||||
public class WeeklyReportRecord {
|
||||
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
public long id;
|
||||
public String reportType; // weekly | daily
|
||||
public String inputContent;
|
||||
public String reportContent;
|
||||
public long createdAt;
|
||||
|
||||
public WeeklyReportRecord() {}
|
||||
|
||||
public WeeklyReportRecord(String reportType, String inputContent, String reportContent) {
|
||||
this.reportType = reportType;
|
||||
this.inputContent = inputContent;
|
||||
this.reportContent = reportContent;
|
||||
this.createdAt = System.currentTimeMillis();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.ruilaizi.example.data.db;
|
||||
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.room.Dao;
|
||||
import androidx.room.Insert;
|
||||
import androidx.room.Query;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Dao
|
||||
public interface WeeklyReportRecordDao {
|
||||
|
||||
@Insert
|
||||
long insert(WeeklyReportRecord record);
|
||||
|
||||
@Query("SELECT * FROM weekly_report_records ORDER BY createdAt DESC LIMIT 50")
|
||||
LiveData<List<WeeklyReportRecord>> getRecentRecords();
|
||||
|
||||
@Query("DELETE FROM weekly_report_records WHERE id NOT IN (SELECT id FROM weekly_report_records ORDER BY createdAt DESC LIMIT 50)")
|
||||
void keepOnlyRecent();
|
||||
}
|
||||
@@ -2,19 +2,39 @@ package com.ruilaizi.example.data.meeting;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.lifecycle.LiveData;
|
||||
|
||||
import com.ruilaizi.example.data.api.ApiKeyProvider;
|
||||
import com.ruilaizi.example.data.api.OpenAICompletionService;
|
||||
import com.ruilaizi.example.data.db.AppDatabase;
|
||||
import com.ruilaizi.example.data.db.MeetingMinutesRecord;
|
||||
import com.ruilaizi.example.data.db.MeetingMinutesRecordDao;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class MeetingMinutesRepository {
|
||||
|
||||
private final MeetingMinutesGenerator generator;
|
||||
private final MeetingMinutesRecordDao dao;
|
||||
|
||||
public MeetingMinutesRepository(Context context) {
|
||||
ApiKeyProvider apiKeyProvider = new ApiKeyProvider(context);
|
||||
generator = new MeetingMinutesGenerator(new OpenAICompletionService(null), apiKeyProvider);
|
||||
dao = AppDatabase.getInstance(context).meetingMinutesRecordDao();
|
||||
}
|
||||
|
||||
public String generate(String rawContent, String title) throws Exception {
|
||||
return generator.generate(rawContent, title);
|
||||
}
|
||||
|
||||
public void saveRecord(MeetingMinutesRecord record) {
|
||||
new Thread(() -> {
|
||||
dao.insert(record);
|
||||
dao.keepOnlyRecent();
|
||||
}).start();
|
||||
}
|
||||
|
||||
public LiveData<List<MeetingMinutesRecord>> getRecentRecords() {
|
||||
return dao.getRecentRecords();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.ruilaizi.example.data.poetry;
|
||||
|
||||
import com.ruilaizi.example.data.api.ApiKeyProvider;
|
||||
import com.ruilaizi.example.data.api.OpenAICompletionService;
|
||||
|
||||
public class PoetryGenerator {
|
||||
|
||||
private final OpenAICompletionService completionService;
|
||||
private final ApiKeyProvider apiKeyProvider;
|
||||
|
||||
public PoetryGenerator(OpenAICompletionService completionService, ApiKeyProvider apiKeyProvider) {
|
||||
this.completionService = completionService;
|
||||
this.apiKeyProvider = apiKeyProvider;
|
||||
}
|
||||
|
||||
public String generate(String poetryTitle, String author, String dynasty, String extraRequirements) throws Exception {
|
||||
String apiKey = apiKeyProvider.getApiKey();
|
||||
if (apiKey == null || apiKey.isEmpty()) throw new Exception("请先在设置中配置 API Key");
|
||||
if (poetryTitle == null || poetryTitle.trim().isEmpty()) throw new Exception("请输入诗词标题");
|
||||
String systemPrompt = "你是一位专业的古典文学专家和古诗词翻译家。请根据用户提供的古诗词信息,提供完整的原文、现代译文、详细注释和深度解读。使用 Markdown 格式输出,标题用 # ## ###,重要内容用粗体。";
|
||||
String userPrompt = "诗词标题:" + (poetryTitle != null ? poetryTitle.trim() : "") + "\n作者:" + (author != null ? author : "") + "\n朝代:" + (dynasty != null ? dynasty : "");
|
||||
if (extraRequirements != null && !extraRequirements.isEmpty()) userPrompt += "\n其他要求:" + extraRequirements;
|
||||
userPrompt += "\n\n请提供完整的古诗词解析。";
|
||||
return completionService.chat(systemPrompt, userPrompt, 0.7f, 2000, apiKey);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.ruilaizi.example.data.poetry;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.lifecycle.LiveData;
|
||||
|
||||
import com.ruilaizi.example.data.api.ApiKeyProvider;
|
||||
import com.ruilaizi.example.data.api.OpenAICompletionService;
|
||||
import com.ruilaizi.example.data.db.AppDatabase;
|
||||
import com.ruilaizi.example.data.db.PoetryRecord;
|
||||
import com.ruilaizi.example.data.db.PoetryRecordDao;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class PoetryRepository {
|
||||
|
||||
private final PoetryGenerator generator;
|
||||
private final PoetryRecordDao dao;
|
||||
|
||||
public PoetryRepository(Context context) {
|
||||
ApiKeyProvider apiKeyProvider = new ApiKeyProvider(context);
|
||||
generator = new PoetryGenerator(new OpenAICompletionService(null), apiKeyProvider);
|
||||
dao = AppDatabase.getInstance(context).poetryRecordDao();
|
||||
}
|
||||
|
||||
public String generate(String poetryTitle, String author, String dynasty, String extraRequirements) throws Exception {
|
||||
return generator.generate(poetryTitle, author, dynasty, extraRequirements);
|
||||
}
|
||||
|
||||
public void saveRecord(PoetryRecord record) {
|
||||
new Thread(() -> {
|
||||
dao.insert(record);
|
||||
dao.keepOnlyRecent();
|
||||
}).start();
|
||||
}
|
||||
|
||||
public LiveData<List<PoetryRecord>> getRecentRecords() {
|
||||
return dao.getRecentRecords();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.ruilaizi.example.data.resume;
|
||||
|
||||
import com.ruilaizi.example.data.api.ApiKeyProvider;
|
||||
import com.ruilaizi.example.data.api.OpenAICompletionService;
|
||||
|
||||
/**
|
||||
* 简历/求职信优化生成器,与 Flask resume_optimization 逻辑一致。
|
||||
*/
|
||||
public class ResumeOptimizationGenerator {
|
||||
|
||||
private final OpenAICompletionService completionService;
|
||||
private final ApiKeyProvider apiKeyProvider;
|
||||
|
||||
public ResumeOptimizationGenerator(OpenAICompletionService completionService, ApiKeyProvider apiKeyProvider) {
|
||||
this.completionService = completionService;
|
||||
this.apiKeyProvider = apiKeyProvider;
|
||||
}
|
||||
|
||||
public String generate(String optType, String originalContent, String jobDescription) throws Exception {
|
||||
String apiKey = apiKeyProvider.getApiKey();
|
||||
if (apiKey == null || apiKey.isEmpty()) throw new Exception("请先在设置中配置 API Key");
|
||||
if (originalContent == null || originalContent.trim().isEmpty()) throw new Exception("请填写简历内容或求职信要点");
|
||||
String systemPrompt;
|
||||
String userPrompt;
|
||||
if ("cover_letter".equals(optType)) {
|
||||
systemPrompt = "你是一位专业的求职顾问,擅长根据简历和岗位描述撰写针对性的求职信。要求:根据用户提供的简历要点和岗位描述(如有),写一封简洁、得体的求职信。结构建议:开头称呼与应聘意向、与岗位匹配的经历与能力、结尾表达意愿与感谢。语气专业、诚恳,篇幅适中(一般 300~500 字)。";
|
||||
userPrompt = "请根据以下内容撰写求职信:\n\n【简历/个人要点】\n" + originalContent.trim() + "\n\n" + (jobDescription != null && !jobDescription.isEmpty() ? "【岗位描述】\n" + jobDescription + "\n" : "");
|
||||
} else {
|
||||
systemPrompt = "你是一位专业的简历优化师,擅长在保持真实的前提下提升简历的呈现效果。要求:根据用户提供的简历内容进行优化:润色表述、突出成果与关键词、调整结构层次。若用户提供了岗位描述,请使经历与能力描述更贴合该岗位。输出使用 Markdown 格式,保持条理清晰。不要编造经历或数据,仅做表述优化。";
|
||||
userPrompt = "请优化以下简历内容:\n\n" + originalContent.trim() + "\n\n" + (jobDescription != null && !jobDescription.isEmpty() ? "【岗位描述(供针对性优化)】\n" + jobDescription + "\n" : "");
|
||||
}
|
||||
return completionService.chat(systemPrompt, userPrompt, 0.5f, 2000, apiKey);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.ruilaizi.example.data.resume;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.lifecycle.LiveData;
|
||||
|
||||
import com.ruilaizi.example.data.api.ApiKeyProvider;
|
||||
import com.ruilaizi.example.data.api.OpenAICompletionService;
|
||||
import com.ruilaizi.example.data.db.AppDatabase;
|
||||
import com.ruilaizi.example.data.db.ResumeOptimizationRecord;
|
||||
import com.ruilaizi.example.data.db.ResumeOptimizationRecordDao;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class ResumeOptimizationRepository {
|
||||
|
||||
private final ResumeOptimizationGenerator generator;
|
||||
private final ResumeOptimizationRecordDao dao;
|
||||
|
||||
public ResumeOptimizationRepository(Context context) {
|
||||
ApiKeyProvider apiKeyProvider = new ApiKeyProvider(context);
|
||||
generator = new ResumeOptimizationGenerator(new OpenAICompletionService(null), apiKeyProvider);
|
||||
dao = AppDatabase.getInstance(context).resumeOptimizationRecordDao();
|
||||
}
|
||||
|
||||
public String generate(String optType, String originalContent, String jobDescription) throws Exception {
|
||||
return generator.generate(optType, originalContent, jobDescription);
|
||||
}
|
||||
|
||||
public void saveRecord(ResumeOptimizationRecord record) {
|
||||
new Thread(() -> {
|
||||
dao.insert(record);
|
||||
dao.keepOnlyRecent();
|
||||
}).start();
|
||||
}
|
||||
|
||||
public LiveData<List<ResumeOptimizationRecord>> getRecentRecords() {
|
||||
return dao.getRecentRecords();
|
||||
}
|
||||
}
|
||||
@@ -2,19 +2,39 @@ package com.ruilaizi.example.data.travel;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.lifecycle.LiveData;
|
||||
|
||||
import com.ruilaizi.example.data.api.ApiKeyProvider;
|
||||
import com.ruilaizi.example.data.api.OpenAICompletionService;
|
||||
import com.ruilaizi.example.data.db.AppDatabase;
|
||||
import com.ruilaizi.example.data.db.TravelPlanRecord;
|
||||
import com.ruilaizi.example.data.db.TravelPlanRecordDao;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class TravelPlanningRepository {
|
||||
|
||||
private final TravelPlanGenerator generator;
|
||||
private final TravelPlanRecordDao dao;
|
||||
|
||||
public TravelPlanningRepository(Context context) {
|
||||
ApiKeyProvider apiKeyProvider = new ApiKeyProvider(context);
|
||||
generator = new TravelPlanGenerator(new OpenAICompletionService(null), apiKeyProvider);
|
||||
dao = AppDatabase.getInstance(context).travelPlanRecordDao();
|
||||
}
|
||||
|
||||
public String generate(String destination, String days, String people, String preferences, String budget) throws Exception {
|
||||
return generator.generate(destination, days, people, preferences, budget);
|
||||
}
|
||||
|
||||
public void saveRecord(TravelPlanRecord record) {
|
||||
new Thread(() -> {
|
||||
dao.insert(record);
|
||||
dao.keepOnlyRecent();
|
||||
}).start();
|
||||
}
|
||||
|
||||
public LiveData<List<TravelPlanRecord>> getRecentRecords() {
|
||||
return dao.getRecentRecords();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,19 +2,39 @@ package com.ruilaizi.example.data.weekly;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.lifecycle.LiveData;
|
||||
|
||||
import com.ruilaizi.example.data.api.ApiKeyProvider;
|
||||
import com.ruilaizi.example.data.api.OpenAICompletionService;
|
||||
import com.ruilaizi.example.data.db.AppDatabase;
|
||||
import com.ruilaizi.example.data.db.WeeklyReportRecord;
|
||||
import com.ruilaizi.example.data.db.WeeklyReportRecordDao;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class WeeklyReportRepository {
|
||||
|
||||
private final WeeklyReportGenerator generator;
|
||||
private final WeeklyReportRecordDao dao;
|
||||
|
||||
public WeeklyReportRepository(Context context) {
|
||||
ApiKeyProvider apiKeyProvider = new ApiKeyProvider(context);
|
||||
generator = new WeeklyReportGenerator(new OpenAICompletionService(null), apiKeyProvider);
|
||||
dao = AppDatabase.getInstance(context).weeklyReportRecordDao();
|
||||
}
|
||||
|
||||
public String generate(String reportType, String content) throws Exception {
|
||||
return generator.generate(reportType, content);
|
||||
}
|
||||
|
||||
public void saveRecord(WeeklyReportRecord record) {
|
||||
new Thread(() -> {
|
||||
dao.insert(record);
|
||||
dao.keepOnlyRecent();
|
||||
}).start();
|
||||
}
|
||||
|
||||
public LiveData<List<WeeklyReportRecord>> getRecentRecords() {
|
||||
return dao.getRecentRecords();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,6 +39,9 @@ public class MeetingMinutesViewModel extends AndroidViewModel {
|
||||
try {
|
||||
String summary = repository.generate(rawContent, title);
|
||||
resultLiveData.postValue(summary);
|
||||
if (summary != null && !summary.isEmpty()) {
|
||||
repository.saveRecord(new com.ruilaizi.example.data.db.MeetingMinutesRecord(title, rawContent, summary));
|
||||
}
|
||||
snackbarLiveData.postValue("会议纪要生成完成");
|
||||
} catch (Exception e) {
|
||||
errorLiveData.postValue(e != null ? e.getMessage() : "生成失败");
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
package com.ruilaizi.example.ui;
|
||||
|
||||
import android.app.Application;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.lifecycle.AndroidViewModel;
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
|
||||
import com.ruilaizi.example.data.db.PoetryRecord;
|
||||
import com.ruilaizi.example.data.poetry.PoetryRepository;
|
||||
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
public class PoetryViewModel extends AndroidViewModel {
|
||||
|
||||
private final PoetryRepository repository;
|
||||
private final ExecutorService executor = Executors.newSingleThreadExecutor();
|
||||
private final MutableLiveData<String> resultLiveData = new MutableLiveData<>("");
|
||||
private final MutableLiveData<Boolean> loadingLiveData = new MutableLiveData<>(false);
|
||||
private final MutableLiveData<String> errorLiveData = new MutableLiveData<>();
|
||||
private final MutableLiveData<String> snackbarLiveData = new MutableLiveData<>();
|
||||
|
||||
public PoetryViewModel(@NonNull Application app) {
|
||||
super(app);
|
||||
repository = new PoetryRepository(app);
|
||||
}
|
||||
|
||||
public LiveData<String> getResultLiveData() { return resultLiveData; }
|
||||
public LiveData<Boolean> getLoadingLiveData() { return loadingLiveData; }
|
||||
public LiveData<String> getErrorLiveData() { return errorLiveData; }
|
||||
public LiveData<String> getSnackbarLiveData() { return snackbarLiveData; }
|
||||
|
||||
public void generate(String poetryTitle, String author, String dynasty, String extraRequirements) {
|
||||
loadingLiveData.setValue(true);
|
||||
resultLiveData.setValue("");
|
||||
errorLiveData.setValue(null);
|
||||
executor.execute(() -> {
|
||||
try {
|
||||
String content = repository.generate(poetryTitle, author, dynasty, extraRequirements);
|
||||
resultLiveData.postValue(content);
|
||||
if (content != null && !content.isEmpty()) {
|
||||
repository.saveRecord(new PoetryRecord(poetryTitle, author, dynasty, content));
|
||||
}
|
||||
snackbarLiveData.postValue("古诗词解析完成");
|
||||
} catch (Exception e) {
|
||||
errorLiveData.postValue(e != null ? e.getMessage() : "生成失败");
|
||||
} finally {
|
||||
loadingLiveData.postValue(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void clearError() { errorLiveData.setValue(null); }
|
||||
public void clearSnackbar() { snackbarLiveData.setValue(null); }
|
||||
|
||||
@Override
|
||||
protected void onCleared() {
|
||||
executor.shutdown();
|
||||
super.onCleared();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package com.ruilaizi.example.ui;
|
||||
|
||||
import android.app.Application;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.lifecycle.AndroidViewModel;
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
|
||||
import com.ruilaizi.example.data.db.ResumeOptimizationRecord;
|
||||
import com.ruilaizi.example.data.resume.ResumeOptimizationRepository;
|
||||
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
public class ResumeOptimizationViewModel extends AndroidViewModel {
|
||||
|
||||
private final ResumeOptimizationRepository repository;
|
||||
private final ExecutorService executor = Executors.newSingleThreadExecutor();
|
||||
private final MutableLiveData<String> resultLiveData = new MutableLiveData<>("");
|
||||
private final MutableLiveData<Boolean> loadingLiveData = new MutableLiveData<>(false);
|
||||
private final MutableLiveData<String> errorLiveData = new MutableLiveData<>();
|
||||
private final MutableLiveData<String> snackbarLiveData = new MutableLiveData<>();
|
||||
|
||||
public ResumeOptimizationViewModel(@NonNull Application app) {
|
||||
super(app);
|
||||
repository = new ResumeOptimizationRepository(app);
|
||||
}
|
||||
|
||||
public LiveData<String> getResultLiveData() { return resultLiveData; }
|
||||
public LiveData<Boolean> getLoadingLiveData() { return loadingLiveData; }
|
||||
public LiveData<String> getErrorLiveData() { return errorLiveData; }
|
||||
public LiveData<String> getSnackbarLiveData() { return snackbarLiveData; }
|
||||
|
||||
public void generate(String optType, String originalContent, String jobDescription) {
|
||||
loadingLiveData.setValue(true);
|
||||
resultLiveData.setValue("");
|
||||
errorLiveData.setValue(null);
|
||||
executor.execute(() -> {
|
||||
try {
|
||||
String content = repository.generate(optType, originalContent, jobDescription);
|
||||
resultLiveData.postValue(content);
|
||||
if (content != null && !content.isEmpty()) {
|
||||
repository.saveRecord(new ResumeOptimizationRecord(optType, originalContent, jobDescription, content));
|
||||
}
|
||||
snackbarLiveData.postValue("优化完成");
|
||||
} catch (Exception e) {
|
||||
errorLiveData.postValue(e != null ? e.getMessage() : "生成失败");
|
||||
} finally {
|
||||
loadingLiveData.postValue(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void clearError() { errorLiveData.setValue(null); }
|
||||
public void clearSnackbar() { snackbarLiveData.setValue(null); }
|
||||
|
||||
@Override
|
||||
protected void onCleared() {
|
||||
executor.shutdown();
|
||||
super.onCleared();
|
||||
}
|
||||
}
|
||||
@@ -39,6 +39,9 @@ public class TravelPlanningViewModel extends AndroidViewModel {
|
||||
try {
|
||||
String plan = repository.generate(destination, days, people, preferences, budget);
|
||||
resultLiveData.postValue(plan);
|
||||
if (plan != null && !plan.isEmpty()) {
|
||||
repository.saveRecord(new com.ruilaizi.example.data.db.TravelPlanRecord(destination, days, people, preferences, budget, plan));
|
||||
}
|
||||
snackbarLiveData.postValue("旅行攻略生成完成");
|
||||
} catch (Exception e) {
|
||||
errorLiveData.postValue(e != null ? e.getMessage() : "生成失败");
|
||||
|
||||
@@ -39,6 +39,9 @@ public class WeeklyReportViewModel extends AndroidViewModel {
|
||||
try {
|
||||
String report = repository.generate(reportType, content);
|
||||
resultLiveData.postValue(report);
|
||||
if (report != null && !report.isEmpty()) {
|
||||
repository.saveRecord(new com.ruilaizi.example.data.db.WeeklyReportRecord(reportType, content, report));
|
||||
}
|
||||
snackbarLiveData.postValue("周报/日报生成完成");
|
||||
} catch (Exception e) {
|
||||
errorLiveData.postValue(e != null ? e.getMessage() : "生成失败");
|
||||
|
||||
@@ -33,7 +33,12 @@
|
||||
android:textStyle="bold"
|
||||
android:textColor="@color/colorPrimary"
|
||||
android:gravity="center" />
|
||||
<View android:layout_width="48dp" android:layout_height="wrap_content" />
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btn_history"
|
||||
style="@style/Widget.MaterialComponents.Button.TextButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/btn_history" />
|
||||
</LinearLayout>
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
<?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"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:background="@color/colorSurface">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical"
|
||||
android:padding="16dp"
|
||||
android:background="@color/colorCard">
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btn_back"
|
||||
style="@style/Widget.MaterialComponents.Button.TextButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/history_back"
|
||||
android:textColor="@color/colorPrimary" />
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/meeting_minutes_history_title"
|
||||
android:textColor="@color/colorPrimary"
|
||||
android:textSize="20sp"
|
||||
android:textStyle="bold" />
|
||||
</LinearLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1">
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/recycler"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:padding="12dp"
|
||||
android:clipToPadding="false"
|
||||
tools:listitem="@layout/item_meeting_minutes_history" />
|
||||
<TextView
|
||||
android:id="@+id/empty_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:text="@string/meeting_minutes_history_empty"
|
||||
android:textColor="@color/colorTextSecondary"
|
||||
android:visibility="gone" />
|
||||
</FrameLayout>
|
||||
</LinearLayout>
|
||||
112
example/app/src/main/res/layout/activity_poetry.xml
Normal file
112
example/app/src/main/res/layout/activity_poetry.xml
Normal file
@@ -0,0 +1,112 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ScrollView 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:background="@color/colorSurface"
|
||||
android:fillViewport="true">
|
||||
|
||||
<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"
|
||||
android:layout_marginBottom="16dp">
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btn_back"
|
||||
style="@style/Widget.MaterialComponents.Button.TextButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="返回" />
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="古诗词解析"
|
||||
android:textSize="20sp"
|
||||
android:textStyle="bold"
|
||||
android:textColor="@color/colorPrimary"
|
||||
android:gravity="center" />
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btn_history"
|
||||
style="@style/Widget.MaterialComponents.Button.TextButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/btn_history" />
|
||||
</LinearLayout>
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:cardBackgroundColor="@color/colorCard"
|
||||
app:cardElevation="2dp"
|
||||
app:cardCornerRadius="12dp"
|
||||
android:layout_marginBottom="16dp">
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="诗词标题 *" android:textSize="12sp" android:textColor="@color/colorTextSecondary" android:layout_marginBottom="4dp" />
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/et_poetry_title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="如:静夜思"
|
||||
android:layout_marginBottom="12dp" />
|
||||
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="作者" android:textSize="12sp" android:textColor="@color/colorTextSecondary" android:layout_marginBottom="4dp" />
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/et_author"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="如:李白"
|
||||
android:layout_marginBottom="12dp" />
|
||||
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="朝代" android:textSize="12sp" android:textColor="@color/colorTextSecondary" android:layout_marginBottom="4dp" />
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/et_dynasty"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="如:唐"
|
||||
android:layout_marginBottom="12dp" />
|
||||
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="其他要求(选填)" android:textSize="12sp" android:textColor="@color/colorTextSecondary" android:layout_marginBottom="4dp" />
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/et_extra"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minLines="2"
|
||||
android:hint="翻译风格、解读深度等"
|
||||
android:inputType="textMultiLine"
|
||||
android:layout_marginBottom="16dp" />
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btn_generate"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="48dp"
|
||||
android:text="生成解析"
|
||||
app:backgroundTint="@color/colorPrimary"
|
||||
android:textColor="@color/colorWhite" />
|
||||
</LinearLayout>
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
<ProgressBar android:id="@+id/progress_bar" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:visibility="gone" android:layout_marginBottom="12dp" />
|
||||
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="解析结果" android:textSize="12sp" android:textColor="@color/colorTextSecondary" android:layout_marginBottom="8dp" />
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:cardBackgroundColor="@color/colorCard"
|
||||
app:cardElevation="2dp"
|
||||
app:cardCornerRadius="12dp"
|
||||
android:minHeight="80dp"
|
||||
android:layout_marginBottom="12dp">
|
||||
<ScrollView android:layout_width="match_parent" android:layout_height="wrap_content" android:fillViewport="true" android:padding="16dp">
|
||||
<TextView android:id="@+id/tv_result" android:layout_width="match_parent" android:layout_height="wrap_content" android:textSize="14sp" android:lineSpacingMultiplier="1.2" android:textColor="@color/colorText" />
|
||||
</ScrollView>
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
<com.google.android.material.button.MaterialButton android:id="@+id/btn_copy" style="@style/Widget.MaterialComponents.Button.OutlinedButton" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/btn_copy" />
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
54
example/app/src/main/res/layout/activity_poetry_history.xml
Normal file
54
example/app/src/main/res/layout/activity_poetry_history.xml
Normal file
@@ -0,0 +1,54 @@
|
||||
<?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"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:background="@color/colorSurface">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical"
|
||||
android:padding="16dp"
|
||||
android:background="@color/colorCard">
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btn_back"
|
||||
style="@style/Widget.MaterialComponents.Button.TextButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/history_back"
|
||||
android:textColor="@color/colorPrimary" />
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/poetry_history_title"
|
||||
android:textColor="@color/colorPrimary"
|
||||
android:textSize="20sp"
|
||||
android:textStyle="bold" />
|
||||
</LinearLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1">
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/recycler"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:padding="12dp"
|
||||
android:clipToPadding="false"
|
||||
tools:listitem="@layout/item_poetry_history" />
|
||||
<TextView
|
||||
android:id="@+id/empty_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:text="@string/poetry_history_empty"
|
||||
android:textColor="@color/colorTextSecondary"
|
||||
android:visibility="gone" />
|
||||
</FrameLayout>
|
||||
</LinearLayout>
|
||||
106
example/app/src/main/res/layout/activity_resume_optimization.xml
Normal file
106
example/app/src/main/res/layout/activity_resume_optimization.xml
Normal file
@@ -0,0 +1,106 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ScrollView 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:background="@color/colorSurface"
|
||||
android:fillViewport="true">
|
||||
|
||||
<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"
|
||||
android:layout_marginBottom="16dp">
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btn_back"
|
||||
style="@style/Widget.MaterialComponents.Button.TextButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="返回" />
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="简历/求职信优化"
|
||||
android:textSize="20sp"
|
||||
android:textStyle="bold"
|
||||
android:textColor="@color/colorPrimary"
|
||||
android:gravity="center" />
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btn_history"
|
||||
style="@style/Widget.MaterialComponents.Button.TextButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/btn_history" />
|
||||
</LinearLayout>
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:cardBackgroundColor="@color/colorCard"
|
||||
app:cardElevation="2dp"
|
||||
app:cardCornerRadius="12dp"
|
||||
android:layout_marginBottom="16dp">
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="类型" android:textSize="12sp" android:textColor="@color/colorTextSecondary" android:layout_marginBottom="4dp" />
|
||||
<Spinner
|
||||
android:id="@+id/spinner_type"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="48dp"
|
||||
android:layout_marginBottom="12dp" />
|
||||
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="简历内容/个人要点 *" android:textSize="12sp" android:textColor="@color/colorTextSecondary" android:layout_marginBottom="4dp" />
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/et_original"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minLines="4"
|
||||
android:hint="粘贴简历内容或要点…"
|
||||
android:inputType="textMultiLine"
|
||||
android:layout_marginBottom="12dp" />
|
||||
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="岗位描述(选填)" android:textSize="12sp" android:textColor="@color/colorTextSecondary" android:layout_marginBottom="4dp" />
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/et_job_desc"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minLines="2"
|
||||
android:hint="岗位描述便于针对性优化"
|
||||
android:inputType="textMultiLine"
|
||||
android:layout_marginBottom="16dp" />
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btn_generate"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="48dp"
|
||||
android:text="生成优化"
|
||||
app:backgroundTint="@color/colorPrimary"
|
||||
android:textColor="@color/colorWhite" />
|
||||
</LinearLayout>
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
<ProgressBar android:id="@+id/progress_bar" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:visibility="gone" android:layout_marginBottom="12dp" />
|
||||
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="优化结果" android:textSize="12sp" android:textColor="@color/colorTextSecondary" android:layout_marginBottom="8dp" />
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:cardBackgroundColor="@color/colorCard"
|
||||
app:cardElevation="2dp"
|
||||
app:cardCornerRadius="12dp"
|
||||
android:minHeight="80dp"
|
||||
android:layout_marginBottom="12dp">
|
||||
<ScrollView android:layout_width="match_parent" android:layout_height="wrap_content" android:fillViewport="true" android:padding="16dp">
|
||||
<TextView android:id="@+id/tv_result" android:layout_width="match_parent" android:layout_height="wrap_content" android:textSize="14sp" android:lineSpacingMultiplier="1.2" android:textColor="@color/colorText" />
|
||||
</ScrollView>
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
<com.google.android.material.button.MaterialButton android:id="@+id/btn_copy" style="@style/Widget.MaterialComponents.Button.OutlinedButton" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/btn_copy" />
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
@@ -0,0 +1,54 @@
|
||||
<?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"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:background="@color/colorSurface">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical"
|
||||
android:padding="16dp"
|
||||
android:background="@color/colorCard">
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btn_back"
|
||||
style="@style/Widget.MaterialComponents.Button.TextButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/history_back"
|
||||
android:textColor="@color/colorPrimary" />
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/resume_history_title"
|
||||
android:textColor="@color/colorPrimary"
|
||||
android:textSize="20sp"
|
||||
android:textStyle="bold" />
|
||||
</LinearLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1">
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/recycler"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:padding="12dp"
|
||||
android:clipToPadding="false"
|
||||
tools:listitem="@layout/item_resume_history" />
|
||||
<TextView
|
||||
android:id="@+id/empty_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:text="@string/resume_history_empty"
|
||||
android:textColor="@color/colorTextSecondary"
|
||||
android:visibility="gone" />
|
||||
</FrameLayout>
|
||||
</LinearLayout>
|
||||
@@ -35,7 +35,12 @@
|
||||
android:textSize="20sp"
|
||||
android:textStyle="bold"
|
||||
android:gravity="center" />
|
||||
<View android:layout_width="48dp" android:layout_height="wrap_content" />
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btn_history"
|
||||
style="@style/Widget.MaterialComponents.Button.TextButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/btn_history" />
|
||||
</LinearLayout>
|
||||
|
||||
<!-- 旅行参数卡片 -->
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
<?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"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:background="@color/colorSurface">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical"
|
||||
android:padding="16dp"
|
||||
android:background="@color/colorCard">
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btn_back"
|
||||
style="@style/Widget.MaterialComponents.Button.TextButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/history_back"
|
||||
android:textColor="@color/colorPrimary" />
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/travel_history_title"
|
||||
android:textColor="@color/colorPrimary"
|
||||
android:textSize="20sp"
|
||||
android:textStyle="bold" />
|
||||
</LinearLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1">
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/recycler"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:padding="12dp"
|
||||
android:clipToPadding="false"
|
||||
tools:listitem="@layout/item_travel_history" />
|
||||
<TextView
|
||||
android:id="@+id/empty_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:text="@string/travel_history_empty"
|
||||
android:textColor="@color/colorTextSecondary"
|
||||
android:visibility="gone" />
|
||||
</FrameLayout>
|
||||
</LinearLayout>
|
||||
@@ -31,7 +31,12 @@
|
||||
android:textStyle="bold"
|
||||
android:textColor="@color/colorPrimary"
|
||||
android:gravity="center" />
|
||||
<View android:layout_width="48dp" android:layout_height="wrap_content" />
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btn_history"
|
||||
style="@style/Widget.MaterialComponents.Button.TextButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/btn_history" />
|
||||
</LinearLayout>
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:layout_width="match_parent"
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
<?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"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:background="@color/colorSurface">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical"
|
||||
android:padding="16dp"
|
||||
android:background="@color/colorCard">
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btn_back"
|
||||
style="@style/Widget.MaterialComponents.Button.TextButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/history_back"
|
||||
android:textColor="@color/colorPrimary" />
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/weekly_report_history_title"
|
||||
android:textColor="@color/colorPrimary"
|
||||
android:textSize="20sp"
|
||||
android:textStyle="bold" />
|
||||
</LinearLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1">
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/recycler"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:padding="12dp"
|
||||
android:clipToPadding="false"
|
||||
tools:listitem="@layout/item_weekly_report_history" />
|
||||
<TextView
|
||||
android:id="@+id/empty_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:text="@string/weekly_report_history_empty"
|
||||
android:textColor="@color/colorTextSecondary"
|
||||
android:visibility="gone" />
|
||||
</FrameLayout>
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:cardBackgroundColor="@color/colorCard"
|
||||
app:cardElevation="2dp"
|
||||
app:cardCornerRadius="12dp"
|
||||
android:layout_marginBottom="12dp">
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
<TextView android:id="@+id/tv_summary" android:layout_width="match_parent" android:layout_height="wrap_content" android:textColor="@color/colorTextDark" android:textSize="14sp" android:maxLines="2" android:ellipsize="end" tools:text="产品需求评审" />
|
||||
<TextView android:id="@+id/tv_content_preview" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="6dp" android:textColor="@color/colorText" android:textSize="12sp" android:maxLines="3" android:ellipsize="end" tools:text="一、会议概要…" />
|
||||
<TextView android:id="@+id/tv_time" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="6dp" android:textColor="@color/colorTextSecondary" android:textSize="11sp" tools:text="2025-03-02 14:30" />
|
||||
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:layout_marginTop="8dp">
|
||||
<com.google.android.material.button.MaterialButton android:id="@+id/btn_use" style="@style/Widget.MaterialComponents.Button.TextButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/history_use" />
|
||||
<com.google.android.material.button.MaterialButton android:id="@+id/btn_copy" style="@style/Widget.MaterialComponents.Button.TextButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/btn_copy" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
24
example/app/src/main/res/layout/item_poetry_history.xml
Normal file
24
example/app/src/main/res/layout/item_poetry_history.xml
Normal file
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:cardBackgroundColor="@color/colorCard"
|
||||
app:cardElevation="2dp"
|
||||
app:cardCornerRadius="12dp"
|
||||
android:layout_marginBottom="12dp">
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
<TextView android:id="@+id/tv_summary" android:layout_width="match_parent" android:layout_height="wrap_content" android:textColor="@color/colorTextDark" android:textSize="14sp" android:maxLines="2" android:ellipsize="end" tools:text="产品需求评审" />
|
||||
<TextView android:id="@+id/tv_content_preview" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="6dp" android:textColor="@color/colorText" android:textSize="12sp" android:maxLines="3" android:ellipsize="end" tools:text="一、会议概要…" />
|
||||
<TextView android:id="@+id/tv_time" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="6dp" android:textColor="@color/colorTextSecondary" android:textSize="11sp" tools:text="2025-03-02 14:30" />
|
||||
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:layout_marginTop="8dp">
|
||||
<com.google.android.material.button.MaterialButton android:id="@+id/btn_use" style="@style/Widget.MaterialComponents.Button.TextButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/history_use" />
|
||||
<com.google.android.material.button.MaterialButton android:id="@+id/btn_copy" style="@style/Widget.MaterialComponents.Button.TextButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/btn_copy" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
24
example/app/src/main/res/layout/item_resume_history.xml
Normal file
24
example/app/src/main/res/layout/item_resume_history.xml
Normal file
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:cardBackgroundColor="@color/colorCard"
|
||||
app:cardElevation="2dp"
|
||||
app:cardCornerRadius="12dp"
|
||||
android:layout_marginBottom="12dp">
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
<TextView android:id="@+id/tv_summary" android:layout_width="match_parent" android:layout_height="wrap_content" android:textColor="@color/colorTextDark" android:textSize="14sp" android:maxLines="2" android:ellipsize="end" tools:text="产品需求评审" />
|
||||
<TextView android:id="@+id/tv_content_preview" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="6dp" android:textColor="@color/colorText" android:textSize="12sp" android:maxLines="3" android:ellipsize="end" tools:text="一、会议概要…" />
|
||||
<TextView android:id="@+id/tv_time" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="6dp" android:textColor="@color/colorTextSecondary" android:textSize="11sp" tools:text="2025-03-02 14:30" />
|
||||
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:layout_marginTop="8dp">
|
||||
<com.google.android.material.button.MaterialButton android:id="@+id/btn_use" style="@style/Widget.MaterialComponents.Button.TextButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/history_use" />
|
||||
<com.google.android.material.button.MaterialButton android:id="@+id/btn_copy" style="@style/Widget.MaterialComponents.Button.TextButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/btn_copy" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
67
example/app/src/main/res/layout/item_travel_history.xml
Normal file
67
example/app/src/main/res/layout/item_travel_history.xml
Normal file
@@ -0,0 +1,67 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:cardBackgroundColor="@color/colorCard"
|
||||
app:cardElevation="2dp"
|
||||
app:cardCornerRadius="12dp"
|
||||
android:layout_marginBottom="12dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_summary"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="@color/colorTextDark"
|
||||
android:textSize="14sp"
|
||||
android:maxLines="2"
|
||||
android:ellipsize="end"
|
||||
tools:text="家乡:四川 | 午餐 | 2人 | 50-100元" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_content_preview"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="6dp"
|
||||
android:textColor="@color/colorText"
|
||||
android:textSize="12sp"
|
||||
android:maxLines="3"
|
||||
android:ellipsize="end"
|
||||
tools:text="一、菜品推荐与搭配思路…" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_time"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="6dp"
|
||||
android:textColor="@color/colorTextSecondary"
|
||||
android:textSize="11sp"
|
||||
tools:text="2025-03-02 14:30" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:layout_marginTop="8dp">
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btn_use"
|
||||
style="@style/Widget.MaterialComponents.Button.TextButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/history_use" />
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btn_copy"
|
||||
style="@style/Widget.MaterialComponents.Button.TextButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/btn_copy" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:cardBackgroundColor="@color/colorCard"
|
||||
app:cardElevation="2dp"
|
||||
app:cardCornerRadius="12dp"
|
||||
android:layout_marginBottom="12dp">
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
<TextView android:id="@+id/tv_summary" android:layout_width="match_parent" android:layout_height="wrap_content" android:textColor="@color/colorTextDark" android:textSize="14sp" android:maxLines="2" android:ellipsize="end" tools:text="周报" />
|
||||
<TextView android:id="@+id/tv_content_preview" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="6dp" android:textColor="@color/colorText" android:textSize="12sp" android:maxLines="3" android:ellipsize="end" tools:text="一、本周工作完成情况…" />
|
||||
<TextView android:id="@+id/tv_time" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="6dp" android:textColor="@color/colorTextSecondary" android:textSize="11sp" tools:text="2025-03-02 14:30" />
|
||||
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:layout_marginTop="8dp">
|
||||
<com.google.android.material.button.MaterialButton android:id="@+id/btn_use" style="@style/Widget.MaterialComponents.Button.TextButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/history_use" />
|
||||
<com.google.android.material.button.MaterialButton android:id="@+id/btn_copy" style="@style/Widget.MaterialComponents.Button.TextButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/btn_copy" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
@@ -19,6 +19,9 @@
|
||||
<item>50元以下</item><item>50-100元</item><item>100-150元</item><item>150-200元</item>
|
||||
<item>200-300元</item><item>300-500元</item><item>500元以上</item>
|
||||
</string-array>
|
||||
<string-array name="resume_opt_types">
|
||||
<item>简历优化</item><item>求职信</item>
|
||||
</string-array>
|
||||
<declare-styleable name="CircleImageView">
|
||||
<attr name="border_width" format="dimension" />
|
||||
<attr name="border_color" format="color" />
|
||||
|
||||
@@ -39,6 +39,16 @@
|
||||
<string name="btn_ai_services">AI应用</string>
|
||||
<string name="meal_planning_history_title">规划历史</string>
|
||||
<string name="meal_planning_history_empty">暂无规划记录</string>
|
||||
<string name="travel_history_title">旅行攻略历史</string>
|
||||
<string name="travel_history_empty">暂无旅行攻略记录</string>
|
||||
<string name="weekly_report_history_title">周报/日报历史</string>
|
||||
<string name="weekly_report_history_empty">暂无周报记录</string>
|
||||
<string name="meeting_minutes_history_title">会议纪要历史</string>
|
||||
<string name="meeting_minutes_history_empty">暂无会议纪要记录</string>
|
||||
<string name="poetry_history_title">古诗词解析历史</string>
|
||||
<string name="poetry_history_empty">暂无解析记录</string>
|
||||
<string name="resume_history_title">简历优化历史</string>
|
||||
<string name="resume_history_empty">暂无优化记录</string>
|
||||
<string name="placeholder_coming_soon">敬请期待</string>
|
||||
<string name="ai_services_title">AI 智能应用</string>
|
||||
<string name="ai_services_subtitle">探索更多 AI 应用</string>
|
||||
|
||||
Reference in New Issue
Block a user