diff --git a/src/Notes-master/src/net/micode/notes/model/ChatMessage.java b/src/Notes-master/src/net/micode/notes/model/ChatMessage.java new file mode 100644 index 0000000..93f2775 --- /dev/null +++ b/src/Notes-master/src/net/micode/notes/model/ChatMessage.java @@ -0,0 +1,16 @@ +package net.micode.notes.model; + +public class ChatMessage { + public long id; + public int senderType; // 0:用户, 1:AI + public int msgType; // 0:普通文本, 1:提醒卡片 + public String content; + public long createdAt; + + public ChatMessage(int senderType, int msgType, String content) { + this.senderType = senderType; + this.msgType = msgType; + this.content = content; + this.createdAt = System.currentTimeMillis(); + } +} \ No newline at end of file diff --git a/src/Notes-master/src/net/micode/notes/ui/AgendaAdapter.java b/src/Notes-master/src/net/micode/notes/ui/AgendaAdapter.java new file mode 100644 index 0000000..65d42b9 --- /dev/null +++ b/src/Notes-master/src/net/micode/notes/ui/AgendaAdapter.java @@ -0,0 +1,103 @@ +package net.micode.notes.ui; + +import android.content.ContentValues; +import android.content.Context; +import android.graphics.Color; +import android.graphics.Paint; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; +import net.micode.notes.R; +import net.micode.notes.data.Notes; +import net.micode.notes.data.Notes.NoteColumns; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class AgendaAdapter extends RecyclerView.Adapter { + + private Context mContext; + private List mData = new ArrayList<>(); + private OnAgendaActionListener mListener; + + // [关键修复] 定义接口 + public interface OnAgendaActionListener { + void onToggleComplete(AgendaItem item); + void onDelete(AgendaItem item); + } + + public void setOnAgendaActionListener(OnAgendaActionListener listener) { + this.mListener = listener; + } + + public static class AgendaItem { + public long id; + public String title; + public String timeLabel; + public long startTime; + public boolean isCompleted; + public boolean isSpecificTime() { + return timeLabel != null && timeLabel.contains(":"); + } + } + + public AgendaAdapter(Context context) { + this.mContext = context; + } + + public void updateData(List newList) { + Collections.sort(newList, (a, b) -> { + if (a.isCompleted != b.isCompleted) return a.isCompleted ? 1 : -1; + if (a.isSpecificTime() != b.isSpecificTime()) return a.isSpecificTime() ? -1 : 1; + return Long.compare(a.startTime, b.startTime); + }); + this.mData = newList; + notifyDataSetChanged(); + } + + @NonNull + @Override + public AgendaViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + View view = LayoutInflater.from(mContext).inflate(R.layout.agenda_item, parent, false); + return new AgendaViewHolder(view); + } + + @Override + public void onBindViewHolder(@NonNull AgendaViewHolder holder, int position) { + AgendaItem item = mData.get(position); + holder.tvContent.setText(item.title); + holder.tvTime.setText(item.timeLabel); + + if (item.isCompleted) { + holder.ivCheck.setImageResource(R.drawable.checkbox_checked); + holder.tvContent.setPaintFlags(holder.tvContent.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG); + holder.tvContent.setTextColor(Color.LTGRAY); + } else { + holder.ivCheck.setImageResource(R.drawable.checkbox_unchecked); + holder.tvContent.setPaintFlags(holder.tvContent.getPaintFlags() & (~Paint.STRIKE_THRU_TEXT_FLAG)); + holder.tvContent.setTextColor(Color.parseColor("#333333")); + } + + holder.ivCheck.setOnClickListener(v -> { if (mListener != null) mListener.onToggleComplete(item); }); + holder.btnDelete.setOnClickListener(v -> { if (mListener != null) mListener.onDelete(item); }); + } + + @Override + public int getItemCount() { return mData.size(); } + + public static class AgendaViewHolder extends RecyclerView.ViewHolder { + ImageView ivCheck, btnDelete; + TextView tvTime, tvContent; + public AgendaViewHolder(@NonNull View itemView) { + super(itemView); + ivCheck = itemView.findViewById(R.id.iv_agenda_check); + tvTime = itemView.findViewById(R.id.tv_agenda_time); + tvContent = itemView.findViewById(R.id.tv_agenda_content); + btnDelete = itemView.findViewById(R.id.btn_agenda_delete); + } + } +} \ No newline at end of file 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/FloatingService.java b/src/Notes-master/src/net/micode/notes/ui/FloatingService.java new file mode 100644 index 0000000..268064f --- /dev/null +++ b/src/Notes-master/src/net/micode/notes/ui/FloatingService.java @@ -0,0 +1,109 @@ +package net.micode.notes.ui; + +import android.app.Service; +import android.content.Context; +import android.content.Intent; +import android.graphics.PixelFormat; +import android.os.Build; +import android.os.IBinder; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.MotionEvent; +import android.view.View; +import android.view.WindowManager; +import net.micode.notes.R; +import net.micode.notes.data.Notes; + +public class FloatingService extends Service { + private WindowManager windowManager; + private View floatingView; + private WindowManager.LayoutParams params; + + @Override + public IBinder onBind(Intent intent) { return null; } + + @Override + public void onCreate() { + super.onCreate(); + windowManager = (WindowManager) getSystemService(WINDOW_SERVICE); + floatingView = LayoutInflater.from(this).inflate(R.layout.floating_window, null); + + // 设置布局参数 + int layoutFlag; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + layoutFlag = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; + } else { + layoutFlag = WindowManager.LayoutParams.TYPE_PHONE; + } + + params = new WindowManager.LayoutParams( + WindowManager.LayoutParams.WRAP_CONTENT, + WindowManager.LayoutParams.WRAP_CONTENT, + layoutFlag, + WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, // 保证外部可点击 + PixelFormat.TRANSLUCENT + ); + + params.gravity = Gravity.TOP | Gravity.START; + params.x = 100; + params.y = 100; + + // 挂载到窗口 + windowManager.addView(floatingView, params); + + // 设置交互逻辑 + setupInteraction(); + } + + private void setupInteraction() { + View ball = floatingView.findViewById(R.id.iv_floating_ball); + + ball.setOnTouchListener(new View.OnTouchListener() { + private int initialX, initialY; + private float initialTouchX, initialTouchY; + private long touchStartTime; + + @Override + public boolean onTouch(View v, MotionEvent event) { + switch (event.getAction()) { + case MotionEvent.ACTION_DOWN: + initialX = params.x; + initialY = params.y; + initialTouchX = event.getRawX(); + initialTouchY = event.getRawY(); + touchStartTime = System.currentTimeMillis(); + return true; + + case MotionEvent.ACTION_MOVE: + params.x = initialX + (int) (event.getRawX() - initialTouchX); + params.y = initialY + (int) (event.getRawY() - initialTouchY); + windowManager.updateViewLayout(floatingView, params); + return true; + + case MotionEvent.ACTION_UP: + // 如果按下时间短且移动距离小,判定为点击 + if (System.currentTimeMillis() - touchStartTime < 200) { + openNewNote(); + } + return true; + } + return false; + } + }); + } + + private void openNewNote() { + Intent intent = new Intent(this, NoteEditActivity.class); + intent.setAction(Intent.ACTION_INSERT_OR_EDIT); + intent.putExtra(Notes.INTENT_EXTRA_FOLDER_ID, Notes.ID_ROOT_FOLDER); + // [核心] Service 调起 Activity 必须加此 Flag + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); + startActivity(intent); + } + + @Override + public void onDestroy() { + super.onDestroy(); + if (floatingView != null) windowManager.removeView(floatingView); + } +} \ No newline at end of file