From 7d319cbd0e4573d9f90a64dbad12d3192d943950 Mon Sep 17 00:00:00 2001 From: gy <2293314358@qq.com> Date: Sat, 31 Jan 2026 00:45:45 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E8=BF=98=E5=8E=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/net/micode/notes/ui/ChatAdapter.java | 77 ------------------- 1 file changed, 77 deletions(-) delete mode 100644 src/Notes-master/src/net/micode/notes/ui/ChatAdapter.java diff --git a/src/Notes-master/src/net/micode/notes/ui/ChatAdapter.java b/src/Notes-master/src/net/micode/notes/ui/ChatAdapter.java deleted file mode 100644 index 7882ace..0000000 --- a/src/Notes-master/src/net/micode/notes/ui/ChatAdapter.java +++ /dev/null @@ -1,77 +0,0 @@ -package net.micode.notes.ui; - -import android.graphics.Typeface; -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 net.micode.notes.R; -import net.micode.notes.model.ChatMessage; -import java.util.List; - -public class ChatAdapter extends RecyclerView.Adapter { - private List mMessages; - - public ChatAdapter(List messages) { - this.mMessages = messages; - } - - @Override - public int getItemViewType(int position) { - ChatMessage msg = mMessages.get(position); - if (msg.senderType == 0) return 0; // 用户消息 - if (msg.msgType == 1) return 2; // 提醒卡片 - return 1; // AI 普通回复 - } - - @NonNull - @Override - public ChatViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { - View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_chat_msg, parent, false); - return new ChatViewHolder(view); - } - - @Override - public void onBindViewHolder(@NonNull ChatViewHolder holder, int position) { - ChatMessage msg = mMessages.get(position); - int viewType = getItemViewType(position); - - // 隐藏所有,根据类型显示 - holder.leftLayout.setVisibility(View.GONE); - holder.rightLayout.setVisibility(View.GONE); - - if (viewType == 0) { // 用户 - holder.rightLayout.setVisibility(View.VISIBLE); - holder.tvRight.setText(msg.content); - } else { // AI 或 提醒 - holder.leftLayout.setVisibility(View.VISIBLE); - holder.tvLeft.setText(msg.content); - - if (viewType == 2) { // 提醒特殊样式 - holder.tvLeft.setBackgroundResource(R.drawable.bg_bubble_reminder); - holder.tvLeft.setTypeface(null, Typeface.BOLD); - holder.tvLeft.setText("📅 日程提醒:\n" + msg.content); - } else { - holder.tvLeft.setBackgroundResource(R.drawable.bg_bubble_ai); - holder.tvLeft.setTypeface(null, Typeface.NORMAL); - } - } - } - - @Override - public int getItemCount() { return mMessages.size(); } - - static class ChatViewHolder extends RecyclerView.ViewHolder { - View leftLayout, rightLayout; - TextView tvLeft, tvRight; - ChatViewHolder(View v) { - super(v); - leftLayout = v.findViewById(R.id.ll_left_layout); - rightLayout = v.findViewById(R.id.ll_right_layout); - tvLeft = v.findViewById(R.id.tv_msg_left); - tvRight = v.findViewById(R.id.tv_msg_right); - } - } -} \ No newline at end of file -- 2.34.1 From d2c3476a9f83a394230c6105c3057a472446a5cd Mon Sep 17 00:00:00 2001 From: gy <2293314358@qq.com> Date: Sat, 31 Jan 2026 00:47:02 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E6=96=B0=E5=A2=9EChatFragment.java?= =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E8=81=8A=E5=A4=A9=E4=B8=BB=E8=A6=81=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=E3=80=82=E4=BF=AE=E6=94=B9NoteEditActivity.java?= =?UTF-8?q?=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/net/micode/notes/ui/ChatAdapter.java | 77 +++++++++++++++++++ .../src/net/micode/notes/ui/ChatFragment.java | 49 ++++++++++++ .../micode/notes/ui/NotesListActivity.java | 70 ++++++++++++----- 3 files changed, 175 insertions(+), 21 deletions(-) create mode 100644 src/Notes-master/src/net/micode/notes/ui/ChatAdapter.java create mode 100644 src/Notes-master/src/net/micode/notes/ui/ChatFragment.java diff --git a/src/Notes-master/src/net/micode/notes/ui/ChatAdapter.java b/src/Notes-master/src/net/micode/notes/ui/ChatAdapter.java new file mode 100644 index 0000000..7882ace --- /dev/null +++ b/src/Notes-master/src/net/micode/notes/ui/ChatAdapter.java @@ -0,0 +1,77 @@ +package net.micode.notes.ui; + +import android.graphics.Typeface; +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 net.micode.notes.R; +import net.micode.notes.model.ChatMessage; +import java.util.List; + +public class ChatAdapter extends RecyclerView.Adapter { + private List mMessages; + + public ChatAdapter(List messages) { + this.mMessages = messages; + } + + @Override + public int getItemViewType(int position) { + ChatMessage msg = mMessages.get(position); + if (msg.senderType == 0) return 0; // 用户消息 + if (msg.msgType == 1) return 2; // 提醒卡片 + return 1; // AI 普通回复 + } + + @NonNull + @Override + public ChatViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_chat_msg, parent, false); + return new ChatViewHolder(view); + } + + @Override + public void onBindViewHolder(@NonNull ChatViewHolder holder, int position) { + ChatMessage msg = mMessages.get(position); + int viewType = getItemViewType(position); + + // 隐藏所有,根据类型显示 + holder.leftLayout.setVisibility(View.GONE); + holder.rightLayout.setVisibility(View.GONE); + + if (viewType == 0) { // 用户 + holder.rightLayout.setVisibility(View.VISIBLE); + holder.tvRight.setText(msg.content); + } else { // AI 或 提醒 + holder.leftLayout.setVisibility(View.VISIBLE); + holder.tvLeft.setText(msg.content); + + if (viewType == 2) { // 提醒特殊样式 + holder.tvLeft.setBackgroundResource(R.drawable.bg_bubble_reminder); + holder.tvLeft.setTypeface(null, Typeface.BOLD); + holder.tvLeft.setText("📅 日程提醒:\n" + msg.content); + } else { + holder.tvLeft.setBackgroundResource(R.drawable.bg_bubble_ai); + holder.tvLeft.setTypeface(null, Typeface.NORMAL); + } + } + } + + @Override + public int getItemCount() { return mMessages.size(); } + + static class ChatViewHolder extends RecyclerView.ViewHolder { + View leftLayout, rightLayout; + TextView tvLeft, tvRight; + ChatViewHolder(View v) { + super(v); + leftLayout = v.findViewById(R.id.ll_left_layout); + rightLayout = v.findViewById(R.id.ll_right_layout); + tvLeft = v.findViewById(R.id.tv_msg_left); + tvRight = v.findViewById(R.id.tv_msg_right); + } + } +} \ No newline at end of file diff --git a/src/Notes-master/src/net/micode/notes/ui/ChatFragment.java b/src/Notes-master/src/net/micode/notes/ui/ChatFragment.java new file mode 100644 index 0000000..60aa21e --- /dev/null +++ b/src/Notes-master/src/net/micode/notes/ui/ChatFragment.java @@ -0,0 +1,49 @@ +package net.micode.notes.ui; + +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.EditText; +import androidx.annotation.NonNull; +import androidx.fragment.app.Fragment; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; +import net.micode.notes.R; +import net.micode.notes.model.ChatMessage; +import java.util.ArrayList; +import java.util.List; + +public class ChatFragment extends Fragment { + private RecyclerView mRecyclerView; + private ChatAdapter mAdapter; + private List mMessages = new ArrayList<>(); + private EditText mInput; + + @Override + public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.fragment_chat, container, false); + mRecyclerView = view.findViewById(R.id.rv_chat_list); + mInput = view.findViewById(R.id.et_chat_input); + + mAdapter = new ChatAdapter(mMessages); + mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext())); + mRecyclerView.setAdapter(mAdapter); + + view.findViewById(R.id.btn_chat_send).setOnClickListener(v -> { + String text = mInput.getText().toString().trim(); + if (!text.isEmpty()) { + // 1. 本地插入用户消息 + ChatMessage userMsg = new ChatMessage(0, 0, text); + mMessages.add(userMsg); + mAdapter.notifyItemInserted(mMessages.size() - 1); + mRecyclerView.smoothScrollToPosition(mMessages.size() - 1); + mInput.setText(""); + + // TODO: Step 3 将在此处调用 CozeClient + } + }); + + return view; + } +} \ No newline at end of file diff --git a/src/Notes-master/src/net/micode/notes/ui/NotesListActivity.java b/src/Notes-master/src/net/micode/notes/ui/NotesListActivity.java index ae8108f..9928b28 100644 --- a/src/Notes-master/src/net/micode/notes/ui/NotesListActivity.java +++ b/src/Notes-master/src/net/micode/notes/ui/NotesListActivity.java @@ -67,6 +67,7 @@ import android.graphics.drawable.Drawable; // [新增] 修复错误 3 & 4 import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.view.ActionMode; import androidx.appcompat.widget.Toolbar; +import androidx.fragment.app.Fragment; import net.micode.notes.tool.DataUtils.AppWidgetAttribute; @@ -329,12 +330,6 @@ public class NotesListActivity extends AppCompatActivity implements OnClickListe super.onResume(); applyCustomBackground(); updateViewMode(); - - // [新增] 触发一次性的异步同步任务 - androidx.work.OneTimeWorkRequest syncRequest = - new androidx.work.OneTimeWorkRequest.Builder(net.micode.notes.sync.SyncWorker.class) - .build(); - androidx.work.WorkManager.getInstance(this).enqueue(syncRequest); } private void applyCustomBackground() { @@ -510,9 +505,13 @@ public class NotesListActivity extends AppCompatActivity implements OnClickListe } } else if (itemId == R.id.nav_ai) { - // --- AI 助手(预留) --- findViewById(R.id.fragment_container).setVisibility(View.VISIBLE); if (getSupportActionBar() != null) getSupportActionBar().setTitle("AI 助理"); + + Fragment chatFrag = fm.findFragmentByTag("CHAT"); + if (chatFrag == null) { + ft.replace(R.id.fragment_container, new ChatFragment(), "CHAT"); + } } // 使用 commitAllowingStateLoss 彻底杜绝由于异步同步导致的 Activity 状态丢失闪退 @@ -1389,10 +1388,7 @@ public class NotesListActivity extends AppCompatActivity implements OnClickListe // 移除之前的 menu.clear(),因为这会清空 onCreate 加载的内容 // 仅保留原有的动态逻辑,例如同步按钮的状态切换 if (mState == ListEditState.NOTE_LIST) { - MenuItem syncItem = menu.findItem(R.id.menu_sync); - if (syncItem != null) { - syncItem.setTitle(R.string.menu_sync); // 始终显示“同步” - } + } else if (mState == ListEditState.SUB_FOLDER) { menu.clear(); // 子文件夹模式下可能需要清除并重新加载 getMenuInflater().inflate(R.menu.sub_folder, menu); @@ -1407,6 +1403,9 @@ public class NotesListActivity extends AppCompatActivity implements OnClickListe @Override public boolean onOptionsItemSelected(MenuItem item) { + androidx.work.Data inputData; + androidx.work.OneTimeWorkRequest syncRequest; + switch (item.getItemId()) { case R.id.menu_new_folder: { showCreateOrModifyFolderDialog(true); @@ -1416,18 +1415,47 @@ public class NotesListActivity extends AppCompatActivity implements OnClickListe exportNoteToText(); break; } - case R.id.menu_sync: - // [新增] 弹出提示,告知用户正在同步 - Toast.makeText(this, "正在同步云端便签...", Toast.LENGTH_SHORT).show(); - - // [核心] 触发 WorkManager 立即执行同步 - androidx.work.OneTimeWorkRequest syncRequest = - new androidx.work.OneTimeWorkRequest.Builder(net.micode.notes.sync.SyncWorker.class) - .build(); + // [修改] 处理 Pull (原 Sync) + case R.id.menu_pull: + Toast.makeText(this, "正在从云端拉取数据...", Toast.LENGTH_SHORT).show(); + // 1. 构造参数 + inputData = new androidx.work.Data.Builder() + .putInt(net.micode.notes.sync.SyncWorker.KEY_SYNC_MODE, net.micode.notes.sync.SyncWorker.MODE_PULL) + .build(); + // 2. 构建请求 + syncRequest = new androidx.work.OneTimeWorkRequest.Builder(net.micode.notes.sync.SyncWorker.class) + .setInputData(inputData) + .build(); + // 3. 提交任务 androidx.work.WorkManager.getInstance(this).enqueue(syncRequest); + // [核心修改]:删除原来的 startAsyncNotesListQuery(); + // 改为监听任务状态,只有当任务 SUCCEEDED (成功) 时才刷新列表 + androidx.work.WorkManager.getInstance(this).getWorkInfoByIdLiveData(syncRequest.getId()) + .observe(this, new androidx.lifecycle.Observer() { + @Override + public void onChanged(androidx.work.WorkInfo workInfo) { + if (workInfo != null && workInfo.getState() == androidx.work.WorkInfo.State.SUCCEEDED) { + // 任务真正结束,且数据已入库,此时刷新界面 + startAsyncNotesListQuery(); + Toast.makeText(NotesListActivity.this, "拉取完成", Toast.LENGTH_SHORT).show(); + } + } + }); + break; + // [新增] 处理 Push + case R.id.menu_push: + Toast.makeText(this, "正在上传数据到云端...", Toast.LENGTH_SHORT).show(); - // 刷新列表显示 - startAsyncNotesListQuery(); + // 构造参数:MODE_PUSH + inputData = new androidx.work.Data.Builder() + .putInt(net.micode.notes.sync.SyncWorker.KEY_SYNC_MODE, net.micode.notes.sync.SyncWorker.MODE_PUSH) + .build(); + + syncRequest = new androidx.work.OneTimeWorkRequest.Builder(net.micode.notes.sync.SyncWorker.class) + .setInputData(inputData) + .build(); + + androidx.work.WorkManager.getInstance(this).enqueue(syncRequest); break; case R.id.menu_setting: { startPreferenceActivity(); -- 2.34.1