liuyan_branch
刘焱 2 weeks ago
parent d9c44e6bd1
commit b67d63fc0e

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 圆角矩形 -->
<corners android:radius="10dip" />
<!-- 背景颜色 -->
<solid android:color="#FF6666" />
<!-- 边框 -->
<stroke
android:width="1dip"
android:color="#FF4444" />
</shape>

@ -0,0 +1,170 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path
android:fillColor="#3DDC84"
android:pathData="M0,0h108v108h-108z" />
<path
android:fillColor="#00000000"
android:pathData="M9,0L9,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,0L19,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,0L29,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,0L39,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,0L49,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,0L59,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,0L69,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,0L79,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M89,0L89,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M99,0L99,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,9L108,9"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,19L108,19"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,29L108,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,39L108,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,49L108,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,59L108,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,69L108,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,79L108,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,89L108,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,99L108,99"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,29L89,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,39L89,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,49L89,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,59L89,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,69L89,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,79L89,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,19L29,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,19L39,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,19L49,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,19L59,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,19L69,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,19L79,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
</vector>

@ -0,0 +1,30 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
<aapt:attr name="android:fillColor">
<gradient
android:endX="85.84757"
android:endY="92.4963"
android:startX="42.9492"
android:startY="49.59793"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0" />
<item
android:color="#00000000"
android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
android:strokeWidth="1"
android:strokeColor="#00000000" />
</vector>

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="#FF6200" />
<size
android:width="180dp"
android:height="180dp" />
</shape>

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ListView
android:id="@+id/friend_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:divider="@android:drawable/divider_horizontal_bright"
android:dividerHeight="1dp"
android:padding="8dp" />
</LinearLayout>

@ -0,0 +1,73 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ScrollView
android:id="@+id/sv_note_edit"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:id="@+id/note_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="8dp"
android:background="@android:color/darker_gray">
<TextView
android:id="@+id/tv_modified_date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@android:style/TextAppearance.Medium"
android:textColor="@android:color/primary_text_light" />
</LinearLayout>
<!-- 标题显示区域 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp"
android:background="@android:color/white">
<TextView
android:id="@+id/note_title_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="@android:style/TextAppearance.Large"
android:textColor="@android:color/primary_text_dark"
android:textSize="20sp"
android:gravity="center"
android:paddingBottom="10dp"
android:layout_marginBottom="10dp"
android:fontFamily="sans-serif-medium"
android:background="@null" />
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#CCCCCC" />
</LinearLayout>
<!-- 正文显示区域 -->
<TextView
android:id="@+id/note_edit_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/white"
android:padding="16dp"
android:textAppearance="@android:style/TextAppearance.Medium"
android:textColor="@android:color/primary_text_dark"
android:textSize="16sp" />
</LinearLayout>
</ScrollView>
</LinearLayout>

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ListView
android:id="@+id/friend_note_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:divider="@android:drawable/divider_horizontal_bright"
android:dividerHeight="1dp"
android:padding="8dp" />
</LinearLayout>

@ -0,0 +1,147 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center_horizontal"
android:padding="20dp"
android:background="@android:color/white">
<!-- 应用图标 -->
<ImageView
android:layout_width="100dp"
android:layout_height="100dp"
android:src="@mipmap/ic_launcher"
android:layout_marginBottom="30dp"
android:layout_marginTop="50dp" />
<!-- 应用名称 -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/app_name"
android:textSize="24sp"
android:textStyle="bold"
android:layout_marginBottom="40dp" />
<!-- 登录表单 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="center_horizontal"
android:background="@android:color/white"
android:padding="20dp"
android:elevation="5dp"
android:layout_marginBottom="20dp">
<!-- 用户名输入 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical"
android:layout_marginBottom="15dp">
<TextView
android:layout_width="80dp"
android:layout_height="wrap_content"
android:text="用户名:"
android:textSize="16sp" />
<EditText
android:id="@+id/et_username"
android:layout_width="match_parent"
android:layout_height="40dp"
android:hint="请输入用户名"
android:inputType="text"
android:singleLine="true"
android:background="@android:drawable/editbox_background_normal"
android:paddingLeft="10dp"
android:paddingRight="10dp" />
</LinearLayout>
<!-- 密码输入 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical"
android:layout_marginBottom="20dp">
<TextView
android:layout_width="80dp"
android:layout_height="wrap_content"
android:text="密码:"
android:textSize="16sp" />
<EditText
android:id="@+id/et_password"
android:layout_width="match_parent"
android:layout_height="40dp"
android:hint="请输入密码"
android:inputType="textPassword"
android:singleLine="true"
android:background="@android:drawable/editbox_background_normal"
android:paddingLeft="10dp"
android:paddingRight="10dp" />
</LinearLayout>
<!-- 登录按钮 -->
<Button
android:id="@+id/btn_login"
android:layout_width="match_parent"
android:layout_height="45dp"
android:text="登录"
android:textSize="18sp"
android:textColor="@android:color/white"
android:background="@android:color/holo_orange_light"
android:layout_marginBottom="15dp"
android:onClick="onLoginClick" />
<!-- 注册和忘记密码按钮 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_horizontal">
<Button
android:id="@+id/btn_register"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="注册账号"
android:textSize="14sp"
android:textColor="@android:color/holo_blue_dark"
android:background="@null"
android:onClick="onRegisterClick" />
<View
android:layout_width="1dp"
android:layout_height="20dp"
android:background="@android:color/darker_gray"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp" />
<Button
android:id="@+id/btn_change_password"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="修改密码"
android:textSize="14sp"
android:textColor="@android:color/holo_blue_dark"
android:background="@null"
android:onClick="onChangePasswordClick" />
</LinearLayout>
</LinearLayout>
<!-- 版权信息 -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="© 2024 小米便签"
android:textSize="12sp"
android:textColor="@android:color/darker_gray"
android:layout_marginTop="50dp" />
</LinearLayout>

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#FFFFFF"
android:gravity="center">
<!-- 小米官方logo: 橙色圆形背景白色MI字样 -->
<LinearLayout
android:id="@+id/mi_logo"
android:layout_width="180dp"
android:layout_height="180dp"
android:layout_centerInParent="true"
android:background="@drawable/mi_logo_background"
android:gravity="center"
android:orientation="vertical">
<!-- 使用TextView显示白色MI字样 -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="MI"
android:textColor="#FFFFFF"
android:textSize="120sp"
android:textStyle="bold"
android:fontFamily="sans-serif" />
</LinearLayout>
<!-- 移除应用名称只保留logo -->
</RelativeLayout>

@ -0,0 +1,55 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:background="#f0f0f0">
<!-- 聊天消息列表 -->
<ListView
android:id="@+id/chat_list"
android:layout_width="fill_parent"
android:layout_height="0dip"
android:layout_weight="1"
android:cacheColorHint="@null"
android:divider="@null"
android:dividerHeight="8dip"
android:padding="8dip"
android:scrollbars="vertical" />
<!-- 输入框和发送按钮 -->
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:background="#ffffff"
android:orientation="horizontal"
android:padding="8dip"
android:weightSum="1">
<EditText
android:id="@+id/message_edit_text"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="1"
android:background="@android:drawable/edit_text"
android:hint="输入消息..."
android:inputType="textMultiLine"
android:maxLines="3"
android:padding="8dip"
android:textColor="#000000"
android:textSize="16sp" />
<Button
android:id="@+id/send_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="8dip"
android:background="@android:drawable/btn_default"
android:text="发送"
android:textColor="#ffffff"
android:textSize="16sp" />
</LinearLayout>
</LinearLayout>

@ -0,0 +1,40 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="left"
android:gravity="left"
android:orientation="vertical"
android:padding="4dip">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left"
android:background="#ffffff"
android:orientation="vertical"
android:padding="8dip">
<TextView
android:id="@+id/message_content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left"
android:maxWidth="250dip"
android:padding="4dip"
android:text="消息内容"
android:textColor="#000000"
android:textSize="16sp" />
<TextView
android:id="@+id/message_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left"
android:layout_marginTop="4dip"
android:padding="2dip"
android:text="12:00"
android:textColor="#80000000"
android:textSize="12sp" />
</LinearLayout>
</LinearLayout>

@ -0,0 +1,70 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="left"
android:gravity="left"
android:orientation="vertical"
android:padding="4dip">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left"
android:background="#ffffff"
android:orientation="vertical"
android:padding="8dip">
<!-- 添加"便签"标注 -->
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left"
android:orientation="horizontal"
android:gravity="center">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="[便签]"
android:textColor="#ffffff"
android:textSize="12sp"
android:background="@android:drawable/btn_default_small"
android:paddingLeft="6dip"
android:paddingRight="6dip"
android:paddingTop="2dip"
android:paddingBottom="2dip"
android:layout_marginRight="4dip"
android:backgroundTint="#0000ff" /> <!-- 接收的便签标注使用蓝色 -->
<TextView
android:id="@+id/message_content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left"
android:maxWidth="300dip"
android:padding="4dip"
android:text="便签内容"
android:textColor="#000000"
android:textSize="16sp"
android:clickable="true"
android:focusable="true"
android:background="@android:drawable/btn_default_small"
android:paddingLeft="8dip"
android:paddingRight="8dip"
android:paddingTop="4dip"
android:paddingBottom="4dip" />
</LinearLayout> <!-- 闭合LinearLayout -->
<TextView
android:id="@+id/message_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left"
android:layout_marginTop="4dip"
android:padding="2dip"
android:text="12:00"
android:textColor="#80000000"
android:textSize="12sp" />
</LinearLayout>
</LinearLayout>

@ -0,0 +1,40 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:gravity="right"
android:orientation="vertical"
android:padding="4dip">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:background="@android:drawable/btn_default"
android:orientation="vertical"
android:padding="8dip">
<TextView
android:id="@+id/message_content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:maxWidth="250dip"
android:padding="4dip"
android:text="消息内容"
android:textColor="#ffffff"
android:textSize="16sp" />
<TextView
android:id="@+id/message_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:layout_marginTop="4dip"
android:padding="2dip"
android:text="12:00"
android:textColor="#80ffffff"
android:textSize="12sp" />
</LinearLayout>
</LinearLayout>

@ -0,0 +1,70 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:gravity="right"
android:orientation="vertical"
android:padding="4dip">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:background="@android:drawable/btn_default"
android:orientation="vertical"
android:padding="8dip">
<!-- 添加"便签"标注 -->
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:orientation="horizontal"
android:gravity="center">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="[便签]"
android:textColor="#ffffff"
android:textSize="12sp"
android:background="@android:drawable/btn_default_small"
android:paddingLeft="6dip"
android:paddingRight="6dip"
android:paddingTop="2dip"
android:paddingBottom="2dip"
android:layout_marginRight="4dip"
android:backgroundTint="#ff0000" />
<TextView
android:id="@+id/message_content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:maxWidth="300dip"
android:padding="4dip"
android:text="便签内容"
android:textColor="#ffffff"
android:textSize="16sp"
android:clickable="true"
android:focusable="true"
android:background="@android:drawable/btn_default_small"
android:paddingLeft="8dip"
android:paddingRight="8dip"
android:paddingTop="4dip"
android:paddingBottom="4dip" />
</LinearLayout> <!-- 闭合LinearLayout -->
<TextView
android:id="@+id/message_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:layout_marginTop="4dip"
android:padding="2dip"
android:text="12:00"
android:textColor="#80ffffff"
android:textSize="12sp" />
</LinearLayout>
</LinearLayout>

@ -0,0 +1,150 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="20dp">
<!-- 标题 -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="修改密码"
android:textSize="20sp"
android:textStyle="bold"
android:layout_gravity="center_horizontal"
android:layout_marginBottom="20dp" />
<!-- 用户名输入 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical"
android:layout_marginBottom="15dp">
<TextView
android:layout_width="80dp"
android:layout_height="wrap_content"
android:text="用户名:"
android:textSize="16sp" />
<EditText
android:id="@+id/et_change_username"
android:layout_width="match_parent"
android:layout_height="40dp"
android:hint="请输入用户名"
android:inputType="text"
android:singleLine="true"
android:background="@android:drawable/editbox_background_normal"
android:paddingLeft="10dp"
android:paddingRight="10dp" />
</LinearLayout>
<!-- 当前密码输入 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical"
android:layout_marginBottom="15dp">
<TextView
android:layout_width="80dp"
android:layout_height="wrap_content"
android:text="当前密码:"
android:textSize="16sp" />
<EditText
android:id="@+id/et_current_password"
android:layout_width="match_parent"
android:layout_height="40dp"
android:hint="请输入当前密码"
android:inputType="textPassword"
android:singleLine="true"
android:background="@android:drawable/editbox_background_normal"
android:paddingLeft="10dp"
android:paddingRight="10dp" />
</LinearLayout>
<!-- 新密码输入 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical"
android:layout_marginBottom="15dp">
<TextView
android:layout_width="80dp"
android:layout_height="wrap_content"
android:text="新密码:"
android:textSize="16sp" />
<EditText
android:id="@+id/et_new_password"
android:layout_width="match_parent"
android:layout_height="40dp"
android:hint="请输入新密码"
android:inputType="textPassword"
android:singleLine="true"
android:background="@android:drawable/editbox_background_normal"
android:paddingLeft="10dp"
android:paddingRight="10dp" />
</LinearLayout>
<!-- 确认新密码输入 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical"
android:layout_marginBottom="20dp">
<TextView
android:layout_width="80dp"
android:layout_height="wrap_content"
android:text="确认新密码:"
android:textSize="16sp" />
<EditText
android:id="@+id/et_confirm_new_password"
android:layout_width="match_parent"
android:layout_height="40dp"
android:hint="请再次输入新密码"
android:inputType="textPassword"
android:singleLine="true"
android:background="@android:drawable/editbox_background_normal"
android:paddingLeft="10dp"
android:paddingRight="10dp" />
</LinearLayout>
<!-- 按钮 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_horizontal"
android:layout_marginTop="10dp">
<Button
android:id="@+id/btn_change_cancel"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:text="取消"
android:textSize="16sp"
android:textColor="@android:color/black"
android:background="@android:drawable/btn_default"
android:layout_marginRight="20dp" />
<Button
android:id="@+id/btn_change_confirm"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:text="确认修改"
android:textSize="16sp"
android:textColor="@android:color/white"
android:background="@android:color/holo_orange_light" />
</LinearLayout>
</LinearLayout>

@ -0,0 +1,124 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="20dp">
<!-- 标题 -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="注册账号"
android:textSize="20sp"
android:textStyle="bold"
android:layout_gravity="center_horizontal"
android:layout_marginBottom="20dp" />
<!-- 用户名输入 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical"
android:layout_marginBottom="15dp">
<TextView
android:layout_width="80dp"
android:layout_height="wrap_content"
android:text="用户名:"
android:textSize="16sp" />
<EditText
android:id="@+id/et_register_username"
android:layout_width="match_parent"
android:layout_height="40dp"
android:hint="请输入用户名"
android:inputType="text"
android:singleLine="true"
android:background="@android:drawable/editbox_background_normal"
android:paddingLeft="10dp"
android:paddingRight="10dp" />
</LinearLayout>
<!-- 密码输入 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical"
android:layout_marginBottom="15dp">
<TextView
android:layout_width="80dp"
android:layout_height="wrap_content"
android:text="密码:"
android:textSize="16sp" />
<EditText
android:id="@+id/et_register_password"
android:layout_width="match_parent"
android:layout_height="40dp"
android:hint="请输入密码"
android:inputType="textPassword"
android:singleLine="true"
android:background="@android:drawable/editbox_background_normal"
android:paddingLeft="10dp"
android:paddingRight="10dp" />
</LinearLayout>
<!-- 确认密码输入 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical"
android:layout_marginBottom="20dp">
<TextView
android:layout_width="80dp"
android:layout_height="wrap_content"
android:text="确认密码:"
android:textSize="16sp" />
<EditText
android:id="@+id/et_register_confirm_password"
android:layout_width="match_parent"
android:layout_height="40dp"
android:hint="请再次输入密码"
android:inputType="textPassword"
android:singleLine="true"
android:background="@android:drawable/editbox_background_normal"
android:paddingLeft="10dp"
android:paddingRight="10dp" />
</LinearLayout>
<!-- 按钮 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_horizontal"
android:layout_marginTop="10dp">
<Button
android:id="@+id/btn_register_cancel"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:text="取消"
android:textSize="16sp"
android:textColor="@android:color/black"
android:background="@android:drawable/btn_default"
android:layout_marginRight="20dp" />
<Button
android:id="@+id/btn_register_confirm"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:text="注册"
android:textSize="16sp"
android:textColor="@android:color/white"
android:background="@android:color/holo_orange_light" />
</LinearLayout>
</LinearLayout>

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:id="@+id/friend_username"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@android:style/TextAppearance.Medium"
android:textColor="@android:color/primary_text_light"
android:textSize="16sp" />
</LinearLayout>

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp">
<EditText
android:id="@+id/password_input"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textPassword"
android:hint="@string/preferences_new_password_hint"
android:layout_marginBottom="16dp" />
</LinearLayout>

@ -0,0 +1,52 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:id="@+id/current_password_label"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/preferences_current_password_label"
android:layout_marginBottom="8dp" />
<EditText
android:id="@+id/current_password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textPassword"
android:hint="@string/preferences_current_password_hint"
android:layout_marginBottom="16dp" />
<TextView
android:id="@+id/new_password_label"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/preferences_new_password_label"
android:layout_marginBottom="8dp" />
<EditText
android:id="@+id/new_password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textPassword"
android:hint="@string/preferences_new_password_hint"
android:layout_marginBottom="16dp" />
<TextView
android:id="@+id/confirm_password_label"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/preferences_confirm_password_label"
android:layout_marginBottom="8dp" />
<EditText
android:id="@+id/confirm_password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textPassword"
android:hint="@string/preferences_confirm_password_hint" />
</LinearLayout>

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
<monochrome android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
<monochrome android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 982 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

@ -0,0 +1,7 @@
<resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. -->
<style name="Base.Theme.Notesmaster" parent="Theme.Material3.DayNight.NoActionBar">
<!-- Customize your dark theme here. -->
<!-- <item name="colorPrimary">@color/my_dark_primary</item> -->
</style>
</resources>

@ -0,0 +1,9 @@
<resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. -->
<style name="Base.Theme.Notesmaster" parent="Theme.Material3.DayNight.NoActionBar">
<!-- Customize your light theme here. -->
<!-- <item name="colorPrimary">@color/my_light_primary</item> -->
</style>
<style name="Theme.Notesmaster" parent="Base.Theme.Notesmaster" />
</resources>

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?><!--
Sample backup rules file; uncomment and customize as necessary.
See https://developer.android.com/guide/topics/data/autobackup
for details.
Note: This file is ignored for devices older than API 31
See https://developer.android.com/about/versions/12/backup-restore
-->
<full-backup-content>
<!--
<include domain="sharedpref" path="."/>
<exclude domain="sharedpref" path="device.xml"/>
-->
</full-backup-content>

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?><!--
Sample data extraction rules file; uncomment and customize as necessary.
See https://developer.android.com/about/versions/12/backup-restore#xml-changes
for details.
-->
<data-extraction-rules>
<cloud-backup>
<!-- TODO: Use <include> and <exclude> to control what is backed up.
<include .../>
<exclude .../>
-->
</cloud-backup>
<!--
<device-transfer>
<include .../>
<exclude .../>
</device-transfer>
-->
</data-extraction-rules>

@ -0,0 +1,23 @@
package net.micode.notes.data;
public class Messages {
public interface MessageColumns {
public static final String ID = "id";
public static final String SENDER_ID = "sender_id";
public static final String RECEIVER_ID = "receiver_id";
public static final String CONTENT = "content";
public static final String MESSAGE_TYPE = "message_type";
public static final String CREATED_DATE = "created_date";
public static final String IS_READ = "is_read";
}
public interface MessageType {
public static final int TEXT = 0;
public static final int IMAGE = 1;
public static final int EMOTION = 2;
public static final int NOTE = 3;
}
public static final long ID_INVALID = -1;
}

@ -0,0 +1,31 @@
/*
* Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.micode.notes.data;
public class Users {
public interface UserColumns {
public static final String ID = "_id";
public static final String USERNAME = "username";
public static final String PASSWORD = "password";
public static final String CREATED_DATE = "created_date";
public static final String MODIFIED_DATE = "modified_date";
}
public interface UserConstants {
// 可以添加一些用户相关的常量
}
}

@ -0,0 +1,90 @@
/*
* Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.micode.notes.tool;
import android.text.TextUtils;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Pattern;
/**
* 便
*/
public class CategoryUtil {
// 分类关键词映射表
private static final Map<String, String> CATEGORY_KEYWORDS = new HashMap<>();
static {
// 工作相关
addKeywords("工作", "工作", "任务", "项目", "会议", "报告", "加班", "上班", "下班", "同事", "领导", "客户", "公司");
// 学习相关
addKeywords("学习", "学习", "考试", "作业", "复习", "预习", "课程", "老师", "学生", "学校", "教材", "笔记", "知识点");
// 生活相关
addKeywords("生活", "生活", "日常", "购物", "吃饭", "旅游", "电影", "音乐", "健身", "运动", "休息", "睡觉", "起床");
// 想法相关
addKeywords("想法", "想法", "创意", "灵感", "思考", "感悟", "心得", "体会", "观点", "意见", "建议");
// 待办相关
addKeywords("待办", "待办", "todo", "需要", "必须", "应该", "计划", "安排", "准备");
// 其他默认分类
addKeywords("其他", "");
}
// 批量添加关键词
private static void addKeywords(String category, String... keywords) {
for (String keyword : keywords) {
CATEGORY_KEYWORDS.put(keyword, category);
}
}
/**
* 便
* @param content 便
* @return 3
*/
public static String autoCategorize(String content) {
if (TextUtils.isEmpty(content)) {
return "其他";
}
// 转为小写进行匹配
String lowerContent = content.toLowerCase();
// 遍历关键词,匹配分类
for (Map.Entry<String, String> entry : CATEGORY_KEYWORDS.entrySet()) {
String keyword = entry.getKey();
String category = entry.getValue();
// 跳过空关键词(默认分类)
if (TextUtils.isEmpty(keyword)) {
continue;
}
// 关键词匹配
if (lowerContent.contains(keyword.toLowerCase())) {
return category;
}
}
// 默认分类
return "其他";
}
}

@ -0,0 +1,192 @@
/*
* Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.micode.notes.tool;
import android.content.Context;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.util.Log;
import net.micode.notes.data.NotesDatabaseHelper;
import net.micode.notes.data.Users;
/**
*
*/
public class UserManager {
private static final String TAG = "UserManager";
private static final String PREF_NAME = "user_preferences";
private static final String KEY_CURRENT_USER_ID = "current_user_id";
private static final String KEY_CURRENT_USERNAME = "current_username";
private static UserManager sInstance;
private SharedPreferences mPrefs;
private Context mContext;
private UserManager(Context context) {
mContext = context.getApplicationContext();
mPrefs = mContext.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE);
}
public static synchronized UserManager getInstance(Context context) {
if (sInstance == null) {
sInstance = new UserManager(context);
}
return sInstance;
}
/**
*
* @param userId ID
* @param username
*/
public void saveCurrentUser(long userId, String username) {
SharedPreferences.Editor editor = mPrefs.edit();
editor.putLong(KEY_CURRENT_USER_ID, userId);
editor.putString(KEY_CURRENT_USERNAME, username);
editor.apply();
}
/**
* ID
* @return ID-1
*/
public long getCurrentUserId() {
return mPrefs.getLong(KEY_CURRENT_USER_ID, -1);
}
/**
*
* @return null
*/
public String getCurrentUsername() {
return mPrefs.getString(KEY_CURRENT_USERNAME, null);
}
/**
* 退
*/
public void clearCurrentUser() {
SharedPreferences.Editor editor = mPrefs.edit();
editor.remove(KEY_CURRENT_USER_ID);
editor.remove(KEY_CURRENT_USERNAME);
editor.apply();
}
/**
*
* @return
*/
public boolean isLoggedIn() {
return getCurrentUserId() != -1;
}
/**
*
* @param userId ID
* @param password
* @return
*/
public boolean validatePassword(long userId, String password) {
try {
// 直接访问数据库验证密码
NotesDatabaseHelper helper = NotesDatabaseHelper.getInstance(mContext);
SQLiteDatabase db = helper.getReadableDatabase();
Cursor cursor = null;
try {
String selection = Users.UserColumns.ID + " = ? AND " + Users.UserColumns.PASSWORD + " = ?";
String[] selectionArgs = {String.valueOf(userId), password};
cursor = db.query(
NotesDatabaseHelper.TABLE.USER,
new String[]{Users.UserColumns.ID},
selection,
selectionArgs,
null,
null,
null
);
return cursor != null && cursor.moveToFirst();
} finally {
if (cursor != null) {
cursor.close();
}
}
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
*
* @param userId ID
*/
public void setCurrentUser(long userId) {
try {
// 查询用户的用户名
NotesDatabaseHelper helper = NotesDatabaseHelper.getInstance(mContext);
SQLiteDatabase db = helper.getReadableDatabase();
Cursor cursor = null;
String username = "未知用户";
try {
String selection = Users.UserColumns.ID + " = ?";
String[] selectionArgs = {String.valueOf(userId)};
cursor = db.query(
NotesDatabaseHelper.TABLE.USER,
new String[]{Users.UserColumns.USERNAME},
selection,
selectionArgs,
null,
null,
null
);
if (cursor != null && cursor.moveToFirst()) {
username = cursor.getString(0);
}
} finally {
if (cursor != null) {
cursor.close();
}
}
// 保存当前用户信息
SharedPreferences.Editor editor = mPrefs.edit();
editor.putLong(KEY_CURRENT_USER_ID, userId);
editor.putString(KEY_CURRENT_USERNAME, username);
editor.apply();
} catch (Exception e) {
Log.e(TAG, "Error in setCurrentUser: " + e.getMessage());
e.printStackTrace();
// 即使发生异常也确保保存用户ID避免状态不一致
try {
SharedPreferences.Editor editor = mPrefs.edit();
editor.putLong(KEY_CURRENT_USER_ID, userId);
editor.putString(KEY_CURRENT_USERNAME, "未知用户");
editor.apply();
} catch (Exception innerE) {
Log.e(TAG, "Error in emergency save: " + innerE.getMessage());
innerE.printStackTrace();
}
}
}
}

@ -0,0 +1,432 @@
package net.micode.notes.ui;
import android.app.ActionBar;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import android.text.TextUtils;
import android.graphics.Color;
import net.micode.notes.R;
import net.micode.notes.data.Messages;
import net.micode.notes.data.NotesDatabaseHelper;
import net.micode.notes.tool.UserManager;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
public class ChatActivity extends Activity {
private static final String TAG = "ChatActivity";
private ListView mChatListView;
private EditText mMessageEditText;
private Button mSendButton;
private ChatAdapter mChatAdapter;
private List<ChatMessage> mMessageList;
private NotesDatabaseHelper mDbHelper;
private SQLiteDatabase mDb;
private UserManager mUserManager;
private long mCurrentUserId;
private long mFriendId;
private String mFriendUsername;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
try {
setContentView(R.layout.chat_activity);
// 设置ActionBar
ActionBar actionBar = getActionBar();
if (actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(true);
}
// 获取Intent参数
mFriendId = getIntent().getLongExtra("friend_id", -1);
mFriendUsername = getIntent().getStringExtra("friend_username");
if (mFriendId == -1 || mFriendUsername == null) {
Toast.makeText(this, "无效的好友信息", Toast.LENGTH_SHORT).show();
finish();
return;
}
// 设置ActionBar标题为好友用户名
if (actionBar != null) {
actionBar.setTitle(mFriendUsername);
}
// 初始化数据库
mDbHelper = NotesDatabaseHelper.getInstance(this);
if (mDbHelper != null) {
mDb = mDbHelper.getWritableDatabase();
}
// 初始化UserManager
mUserManager = UserManager.getInstance(this);
if (mUserManager != null) {
mCurrentUserId = mUserManager.getCurrentUserId();
}
// 初始化界面控件
mChatListView = findViewById(R.id.chat_list);
mMessageEditText = findViewById(R.id.message_edit_text);
mSendButton = findViewById(R.id.send_button);
// 初始化消息列表
mMessageList = new ArrayList<>();
mChatAdapter = new ChatAdapter(this, mMessageList, mCurrentUserId);
mChatListView.setAdapter(mChatAdapter);
// 设置发送按钮点击事件
mSendButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
sendMessage();
}
});
// 加载聊天记录
loadChatHistory();
} catch (Exception e) {
Log.e(TAG, "Error in onCreate: " + e.getMessage(), e);
Toast.makeText(this, "聊天界面初始化失败", Toast.LENGTH_SHORT).show();
finish();
}
}
@Override
protected void onResume() {
super.onResume();
try {
// 重新获取当前用户ID确保在账号切换后能使用正确的用户ID
if (mUserManager != null) {
mCurrentUserId = mUserManager.getCurrentUserId();
Log.d(TAG, "Updated current user ID to: " + mCurrentUserId);
}
// 更新适配器的当前用户ID
if (mChatAdapter != null) {
mChatAdapter.mCurrentUserId = mCurrentUserId;
}
// 重新加载聊天记录
loadChatHistory();
} catch (Exception e) {
Log.e(TAG, "Error in onResume: " + e.getMessage(), e);
}
}
@Override
protected void onDestroy() {
super.onDestroy();
// 关闭数据库连接
if (mDb != null && mDb.isOpen()) {
mDb.close();
}
}
@Override
public boolean onOptionsItemSelected(android.view.MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
// 返回上一级活动
finish();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
/**
*
*/
private void loadChatHistory() {
mMessageList.clear();
// 查询聊天记录
String sql = "SELECT * FROM " + NotesDatabaseHelper.TABLE.MESSAGE + " WHERE " +
"(" + Messages.MessageColumns.SENDER_ID + " = ? AND " + Messages.MessageColumns.RECEIVER_ID + " = ?) OR " +
"(" + Messages.MessageColumns.SENDER_ID + " = ? AND " + Messages.MessageColumns.RECEIVER_ID + " = ?) " +
"ORDER BY " + Messages.MessageColumns.CREATED_DATE + " ASC";
Cursor cursor = mDb.rawQuery(sql, new String[]{
String.valueOf(mCurrentUserId), String.valueOf(mFriendId),
String.valueOf(mFriendId), String.valueOf(mCurrentUserId)
});
if (cursor != null) {
while (cursor.moveToNext()) {
long id = cursor.getLong(cursor.getColumnIndexOrThrow(Messages.MessageColumns.ID));
long senderId = cursor.getLong(cursor.getColumnIndexOrThrow(Messages.MessageColumns.SENDER_ID));
long receiverId = cursor.getLong(cursor.getColumnIndexOrThrow(Messages.MessageColumns.RECEIVER_ID));
String content = cursor.getString(cursor.getColumnIndexOrThrow(Messages.MessageColumns.CONTENT));
int messageType = cursor.getInt(cursor.getColumnIndexOrThrow(Messages.MessageColumns.MESSAGE_TYPE));
long createdDate = cursor.getLong(cursor.getColumnIndexOrThrow(Messages.MessageColumns.CREATED_DATE));
int isRead = cursor.getInt(cursor.getColumnIndexOrThrow(Messages.MessageColumns.IS_READ));
mMessageList.add(new ChatMessage(id, senderId, receiverId, content, messageType, createdDate, isRead));
}
cursor.close();
}
// 通知适配器数据变化
mChatAdapter.notifyDataSetChanged();
// 滚动到底部
if (!mMessageList.isEmpty()) {
mChatListView.setSelection(mMessageList.size() - 1);
}
// 将接收到的消息标记为已读
markMessagesAsRead();
}
/**
*
*/
private void sendMessage() {
String content = mMessageEditText.getText().toString().trim();
if (content.isEmpty()) {
Toast.makeText(this, "消息内容不能为空", Toast.LENGTH_SHORT).show();
return;
}
// 创建消息对象
ContentValues values = new ContentValues();
values.put(Messages.MessageColumns.SENDER_ID, mCurrentUserId);
values.put(Messages.MessageColumns.RECEIVER_ID, mFriendId);
values.put(Messages.MessageColumns.CONTENT, content);
values.put(Messages.MessageColumns.MESSAGE_TYPE, Messages.MessageType.TEXT);
values.put(Messages.MessageColumns.CREATED_DATE, System.currentTimeMillis());
values.put(Messages.MessageColumns.IS_READ, 0);
// 插入消息到数据库
long messageId = mDb.insert(NotesDatabaseHelper.TABLE.MESSAGE, null, values);
if (messageId != -1) {
// 清空输入框
mMessageEditText.setText("");
// 重新加载聊天记录
loadChatHistory();
} else {
Toast.makeText(this, "发送失败", Toast.LENGTH_SHORT).show();
Log.e(TAG, "Failed to send message");
}
}
/**
*
*/
private void markMessagesAsRead() {
ContentValues values = new ContentValues();
values.put(Messages.MessageColumns.IS_READ, 1);
int updatedRows = mDb.update(NotesDatabaseHelper.TABLE.MESSAGE, values,
Messages.MessageColumns.SENDER_ID + " = ? AND " + Messages.MessageColumns.RECEIVER_ID + " = ? AND " + Messages.MessageColumns.IS_READ + " = 0",
new String[]{String.valueOf(mFriendId), String.valueOf(mCurrentUserId)});
Log.d(TAG, "Marked " + updatedRows + " messages as read");
}
/**
* 便
*/
private void showNoteDetail(String noteData) {
try {
// 解析便签数据
String[] noteParts = noteData.split("\\|");
if (noteParts.length < 2) {
Toast.makeText(this, "无效的便签数据", Toast.LENGTH_SHORT).show();
return;
}
String noteTitle = noteParts[0];
String noteContent = noteParts[1];
if (TextUtils.isEmpty(noteTitle)) {
noteTitle = "无标题便签";
}
// 创建并显示便签详情对话框
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(noteTitle);
builder.setMessage(noteContent);
builder.setPositiveButton("确定", null);
builder.show();
} catch (Exception e) {
Log.e(TAG, "Error showing note detail: " + e.getMessage(), e);
Toast.makeText(this, "显示便签详情失败", Toast.LENGTH_SHORT).show();
}
}
/**
*
*/
private static class ChatMessage {
long id;
long senderId;
long receiverId;
String content;
int messageType;
long createdDate;
int isRead;
ChatMessage(long id, long senderId, long receiverId, String content, int messageType, long createdDate, int isRead) {
this.id = id;
this.senderId = senderId;
this.receiverId = receiverId;
this.content = content;
this.messageType = messageType;
this.createdDate = createdDate;
this.isRead = isRead;
}
}
/**
*
*/
private static class ChatAdapter extends BaseAdapter {
private static final int VIEW_TYPE_SENT_TEXT = 0;
private static final int VIEW_TYPE_RECEIVED_TEXT = 1;
private static final int VIEW_TYPE_SENT_NOTE = 2;
private static final int VIEW_TYPE_RECEIVED_NOTE = 3;
private Context mContext;
private List<ChatMessage> mMessageList;
public long mCurrentUserId;
private LayoutInflater mInflater;
private SimpleDateFormat mDateFormat;
ChatAdapter(Context context, List<ChatMessage> messageList, long currentUserId) {
mContext = context;
mMessageList = messageList;
mCurrentUserId = currentUserId;
mInflater = LayoutInflater.from(context);
mDateFormat = new SimpleDateFormat("HH:mm");
}
@Override
public int getCount() {
return mMessageList.size();
}
@Override
public Object getItem(int position) {
return mMessageList.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public int getViewTypeCount() {
return 4; // 四种视图类型:发送文本、接收文本、发送便签、接收便签
}
@Override
public int getItemViewType(int position) {
ChatMessage message = mMessageList.get(position);
boolean isSentByMe = message.senderId == mCurrentUserId;
if (message.messageType == Messages.MessageType.NOTE) {
return isSentByMe ? VIEW_TYPE_SENT_NOTE : VIEW_TYPE_RECEIVED_NOTE;
} else {
return isSentByMe ? VIEW_TYPE_SENT_TEXT : VIEW_TYPE_RECEIVED_TEXT;
}
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ChatMessage message = mMessageList.get(position);
boolean isSentByMe = message.senderId == mCurrentUserId;
ViewHolder holder;
if (convertView == null) {
// 根据视图类型选择不同的布局
int viewType = getItemViewType(position);
switch (viewType) {
case VIEW_TYPE_SENT_NOTE:
convertView = mInflater.inflate(R.layout.chat_message_sent_note_item, parent, false);
break;
case VIEW_TYPE_RECEIVED_NOTE:
convertView = mInflater.inflate(R.layout.chat_message_received_note_item, parent, false);
break;
case VIEW_TYPE_SENT_TEXT:
default:
convertView = mInflater.inflate(R.layout.chat_message_sent_item, parent, false);
break;
case VIEW_TYPE_RECEIVED_TEXT:
convertView = mInflater.inflate(R.layout.chat_message_received_item, parent, false);
break;
}
holder = new ViewHolder();
holder.contentTextView = convertView.findViewById(R.id.message_content);
holder.timeTextView = convertView.findViewById(R.id.message_time);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
// 设置消息内容
if (message.messageType == Messages.MessageType.NOTE) {
// 便签类型消息,只显示便签标题
String[] noteData = message.content.split("\\|");
if (noteData.length >= 2) {
String noteTitle = noteData[0];
if (TextUtils.isEmpty(noteTitle)) {
noteTitle = "无标题便签";
}
holder.contentTextView.setText(noteTitle);
// 设置不同的颜色,区分于普通文本消息
holder.contentTextView.setTextColor(Color.BLUE); // 使用蓝色区分便签消息
holder.contentTextView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 点击便签,查看详情
((ChatActivity) mContext).showNoteDetail(message.content);
}
});
}
} else {
// 普通文本消息
holder.contentTextView.setText(message.content);
holder.contentTextView.setOnClickListener(null);
}
// 设置消息时间
Date date = new Date(message.createdDate);
holder.timeTextView.setText(mDateFormat.format(date));
return convertView;
}
private static class ViewHolder {
TextView contentTextView;
TextView timeTextView;
}
}
}

@ -0,0 +1,206 @@
package net.micode.notes.ui;
import android.app.ActionBar;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import net.micode.notes.R;
import net.micode.notes.data.NotesDatabaseHelper;
import net.micode.notes.tool.UserManager;
import net.micode.notes.data.Users;
import java.util.ArrayList;
import java.util.List;
public class FriendManagementActivity extends Activity {
private ListView mFriendListView;
private FriendAdapter mFriendAdapter;
private List<Friend> mFriendList;
private NotesDatabaseHelper mDbHelper;
private SQLiteDatabase mDb;
private UserManager mUserManager;
private long mCurrentUserId;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_friend_management);
// 设置ActionBar
ActionBar actionBar = getActionBar();
if (actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.setTitle("好友管理");
}
// 初始化数据库
mDbHelper = NotesDatabaseHelper.getInstance(this);
mDb = mDbHelper.getWritableDatabase();
// 初始化UserManager
mUserManager = UserManager.getInstance(this);
mCurrentUserId = mUserManager.getCurrentUserId();
// 初始化ListView
mFriendListView = findViewById(R.id.friend_list);
mFriendList = new ArrayList<>();
mFriendAdapter = new FriendAdapter(this, mFriendList);
mFriendListView.setAdapter(mFriendAdapter);
// 设置ListView点击事件
mFriendListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Friend friend = mFriendList.get(position);
// 启动与好友聊天的活动
Intent intent = new Intent(FriendManagementActivity.this, ChatActivity.class);
intent.putExtra("friend_id", friend.id);
intent.putExtra("friend_username", friend.username);
startActivity(intent);
}
});
// 加载好友列表
loadFriendList();
}
@Override
protected void onResume() {
super.onResume();
// 重新加载好友列表
loadFriendList();
}
@Override
protected void onDestroy() {
super.onDestroy();
// 关闭数据库连接
if (mDb != null && mDb.isOpen()) {
mDb.close();
}
}
/**
*
*/
private void loadFriendList() {
mFriendList.clear();
// 查询除当前用户以外的所有用户
Cursor cursor = mDb.query(
NotesDatabaseHelper.TABLE.USER,
new String[]{Users.UserColumns.ID, Users.UserColumns.USERNAME},
Users.UserColumns.ID + " != ?",
new String[]{String.valueOf(mCurrentUserId)},
null,
null,
null
);
if (cursor != null) {
while (cursor.moveToNext()) {
long id = cursor.getLong(cursor.getColumnIndexOrThrow(Users.UserColumns.ID));
String username = cursor.getString(cursor.getColumnIndexOrThrow(Users.UserColumns.USERNAME));
mFriendList.add(new Friend(id, username));
}
cursor.close();
}
// 通知适配器数据变化
mFriendAdapter.notifyDataSetChanged();
// 如果没有好友,显示提示
if (mFriendList.isEmpty()) {
Toast.makeText(this, "暂无其他用户", Toast.LENGTH_SHORT).show();
}
}
/**
*
*/
private static class Friend {
long id;
String username;
Friend(long id, String username) {
this.id = id;
this.username = username;
}
}
/**
*
*/
private static class FriendAdapter extends BaseAdapter {
private Context mContext;
private List<Friend> mFriendList;
private LayoutInflater mInflater;
FriendAdapter(Context context, List<Friend> friendList) {
mContext = context;
mFriendList = friendList;
mInflater = LayoutInflater.from(context);
}
@Override
public int getCount() {
return mFriendList.size();
}
@Override
public Object getItem(int position) {
return mFriendList.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.item_friend, parent, false);
holder = new ViewHolder();
holder.usernameTextView = convertView.findViewById(R.id.friend_username);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
Friend friend = mFriendList.get(position);
holder.usernameTextView.setText(friend.username);
return convertView;
}
private static class ViewHolder {
TextView usernameTextView;
}
}
@Override
public boolean onOptionsItemSelected(android.view.MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
// 返回上一级活动
finish();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
}

@ -0,0 +1,239 @@
package net.micode.notes.ui;
import android.app.ActionBar;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
import net.micode.notes.R;
import net.micode.notes.data.Notes;
public class FriendNoteEditActivity extends Activity {
private TextView mNoteEditor;
private TextView mNoteTitleView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_friend_note_edit);
// 设置ActionBar
ActionBar actionBar = getActionBar();
if (actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.setTitle("查看便签");
}
// 初始化控件
mNoteEditor = findViewById(R.id.note_edit_view);
mNoteTitleView = findViewById(R.id.note_title_view);
// 加载便签数据
if (savedInstanceState == null && !initActivityState(getIntent())) {
finish();
return;
}
initNoteScreen();
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
if (savedInstanceState != null && savedInstanceState.containsKey(Intent.EXTRA_UID)) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.putExtra(Intent.EXTRA_UID, savedInstanceState.getLong(Intent.EXTRA_UID));
intent.putExtra("friend_id", savedInstanceState.getLong("friend_id"));
if (!initActivityState(intent)) {
finish();
return;
}
// 恢复状态后重新初始化界面
initNoteScreen();
}
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
if (getIntent() != null) {
outState.putLong(Intent.EXTRA_UID, getIntent().getLongExtra(Intent.EXTRA_UID, 0));
outState.putLong("friend_id", getIntent().getLongExtra("friend_id", -1));
}
}
private String mNoteContent;
private String mNoteTitle;
private long mModifiedDate;
private boolean initActivityState(Intent intent) {
/**
*
*/
long noteId = intent.getLongExtra(Intent.EXTRA_UID, 0);
long friendId = intent.getLongExtra("friend_id", -1);
if (noteId <= 0 || friendId <= 0) {
Toast.makeText(this, "便签信息错误", Toast.LENGTH_SHORT).show();
finish();
return false;
}
try {
// 查询便签基本信息,包括标题
String[] noteProjection = {
net.micode.notes.data.Notes.NoteColumns.MODIFIED_DATE,
net.micode.notes.data.Notes.NoteColumns.TITLE
};
android.database.Cursor noteCursor = null;
try {
// 使用ContentResolver查询便签基本信息
noteCursor = getContentResolver().query(
android.content.ContentUris.withAppendedId(net.micode.notes.data.Notes.CONTENT_NOTE_URI, noteId),
noteProjection,
null,
null,
null
);
if (noteCursor != null) {
if (noteCursor.moveToFirst()) {
mModifiedDate = noteCursor.getLong(0);
mNoteTitle = noteCursor.getString(1);
}
noteCursor.close();
}
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(this, "查询便签信息失败", Toast.LENGTH_SHORT).show();
}
// 查询便签具体内容这是必须的因为完整内容存储在Data表中
String[] dataProjection = {net.micode.notes.data.Notes.DataColumns.CONTENT};
String dataSelection = net.micode.notes.data.Notes.DataColumns.NOTE_ID + " = ? AND " +
net.micode.notes.data.Notes.DataColumns.MIME_TYPE + " = ?";
String[] dataSelectionArgs = {String.valueOf(noteId), net.micode.notes.data.Notes.DataConstants.NOTE};
android.database.Cursor dataCursor = null;
try {
// 使用ContentResolver查询数据
dataCursor = getContentResolver().query(
net.micode.notes.data.Notes.CONTENT_DATA_URI,
dataProjection,
dataSelection,
dataSelectionArgs,
null
);
if (dataCursor != null) {
if (dataCursor.moveToFirst()) {
mNoteContent = dataCursor.getString(0);
}
dataCursor.close();
}
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(this, "查询便签内容失败", Toast.LENGTH_SHORT).show();
} finally {
if (dataCursor != null) {
dataCursor.close();
}
}
// 如果查询失败,尝试使用数据库直接查询
if (mNoteContent == null || mNoteContent.isEmpty()) {
try {
// 直接使用数据库查询绕过ContentProvider的用户过滤
net.micode.notes.data.NotesDatabaseHelper helper = net.micode.notes.data.NotesDatabaseHelper.getInstance(FriendNoteEditActivity.this);
if (helper != null) {
dataCursor = helper.getReadableDatabase().query(
net.micode.notes.data.NotesDatabaseHelper.TABLE.DATA,
dataProjection,
dataSelection,
dataSelectionArgs,
null,
null,
null
);
if (dataCursor != null) {
if (dataCursor.moveToFirst()) {
mNoteContent = dataCursor.getString(0);
}
dataCursor.close();
}
}
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(this, "直接查询便签内容失败", Toast.LENGTH_SHORT).show();
} finally {
if (dataCursor != null) {
dataCursor.close();
}
}
}
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(this, "初始化便签失败: " + e.getMessage(), Toast.LENGTH_SHORT).show();
finish();
return false;
}
return true;
}
private void initNoteScreen() {
// 显示修改日期
TextView modifiedDateTextView = findViewById(R.id.tv_modified_date);
modifiedDateTextView.setText(android.text.format.DateUtils.formatDateTime(
this, mModifiedDate,
android.text.format.DateUtils.FORMAT_SHOW_DATE |
android.text.format.DateUtils.FORMAT_NUMERIC_DATE |
android.text.format.DateUtils.FORMAT_SHOW_TIME));
// 显示便签标题
if (mNoteTitle != null && !mNoteTitle.isEmpty()) {
mNoteTitleView.setVisibility(View.VISIBLE);
mNoteTitleView.setText(mNoteTitle);
} else {
// 如果没有标题,隐藏标题文本视图
mNoteTitleView.setVisibility(View.GONE);
}
// 显示便签内容,添加调试日志
if (mNoteContent != null && !mNoteContent.isEmpty()) {
mNoteEditor.setText(mNoteContent);
// 设置文本颜色为深色,确保可见
mNoteEditor.setTextColor(getResources().getColor(android.R.color.primary_text_dark));
// 设置背景色为白色,确保可见
mNoteEditor.setBackgroundColor(getResources().getColor(android.R.color.white));
} else {
// 如果内容为空,显示提示文本
mNoteEditor.setText("(空便签)");
mNoteEditor.setTextColor(getResources().getColor(android.R.color.secondary_text_dark));
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// 不显示菜单,因为是只读模式
return false;
}
@Override
public boolean onOptionsItemSelected(android.view.MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
// 返回上一级活动
finish();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
}

@ -0,0 +1,271 @@
package net.micode.notes.ui;
import android.app.ActionBar;
import android.app.Activity;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import net.micode.notes.R;
import net.micode.notes.data.Notes;
import net.micode.notes.data.Notes.NoteColumns;
import net.micode.notes.model.WorkingNote;
import java.util.ArrayList;
import java.util.List;
public class FriendNoteListActivity extends Activity {
private ListView mNoteListView;
private NoteAdapter mNoteAdapter;
private List<Note> mNoteList;
private long mFriendId;
private String mFriendUsername;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_friend_note_list);
// 获取好友信息
mFriendId = getIntent().getLongExtra("friend_id", -1);
mFriendUsername = getIntent().getStringExtra("friend_username");
if (mFriendId == -1 || mFriendUsername == null) {
Toast.makeText(this, "好友信息错误", Toast.LENGTH_SHORT).show();
finish();
return;
}
// 设置ActionBar
ActionBar actionBar = getActionBar();
if (actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.setTitle(mFriendUsername + "的公开便签");
}
// 初始化ListView
mNoteListView = findViewById(R.id.friend_note_list);
mNoteList = new ArrayList<>();
mNoteAdapter = new NoteAdapter(this, mNoteList);
mNoteListView.setAdapter(mNoteAdapter);
// 设置ListView点击事件
mNoteListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Note note = mNoteList.get(position);
// 启动查看便签详情的活动
Intent intent = new Intent(FriendNoteListActivity.this, FriendNoteEditActivity.class);
intent.putExtra(Intent.EXTRA_UID, note.id);
intent.putExtra("friend_id", mFriendId);
startActivity(intent);
}
});
// 加载好友的公开便签
loadFriendNotes();
}
@Override
protected void onResume() {
super.onResume();
// 重新加载好友便签
loadFriendNotes();
}
/**
* 便
*/
private void loadFriendNotes() {
try {
mNoteList.clear();
// 查询好友的所有公开便签
String[] projection = {
NoteColumns.ID,
NoteColumns.TITLE,
NoteColumns.SNIPPET,
NoteColumns.MODIFIED_DATE,
NoteColumns.TYPE,
NoteColumns.PINNED,
NoteColumns.LOCKED,
NoteColumns.PUBLIC
};
String selection = NoteColumns.USER_ID + " = ? AND " + NoteColumns.PUBLIC + " = 1 AND " + NoteColumns.PARENT_ID + " <> " + Notes.ID_TRASH_FOLER;
String[] selectionArgs = {String.valueOf(mFriendId)};
Cursor cursor = null;
try {
cursor = getContentResolver().query(
Notes.CONTENT_NOTE_URI,
projection,
selection,
selectionArgs,
NoteColumns.PINNED + " DESC, " + NoteColumns.MODIFIED_DATE + " DESC"
);
if (cursor != null) {
while (cursor.moveToNext()) {
long id = cursor.getLong(cursor.getColumnIndexOrThrow(NoteColumns.ID));
String title = cursor.getString(cursor.getColumnIndexOrThrow(NoteColumns.TITLE));
String content = cursor.getString(cursor.getColumnIndexOrThrow(NoteColumns.SNIPPET));
long modifiedDate = cursor.getLong(cursor.getColumnIndexOrThrow(NoteColumns.MODIFIED_DATE));
int type = cursor.getInt(cursor.getColumnIndexOrThrow(NoteColumns.TYPE));
int pinned = cursor.getInt(cursor.getColumnIndexOrThrow(NoteColumns.PINNED));
int locked = cursor.getInt(cursor.getColumnIndexOrThrow(NoteColumns.LOCKED));
int isPublic = cursor.getInt(cursor.getColumnIndexOrThrow(NoteColumns.PUBLIC));
mNoteList.add(new Note(id, title, content, modifiedDate, type, pinned, locked, isPublic));
}
}
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(this, "查询好友便签失败: " + e.getMessage(), Toast.LENGTH_SHORT).show();
} finally {
if (cursor != null) {
cursor.close();
}
}
// 通知适配器数据变化
mNoteAdapter.notifyDataSetChanged();
// 如果没有公开便签,显示提示
if (mNoteList.isEmpty()) {
Toast.makeText(this, mFriendUsername + "没有公开的便签", Toast.LENGTH_SHORT).show();
}
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(this, "加载好友便签失败", Toast.LENGTH_SHORT).show();
}
}
/**
* 便
*/
private static class Note {
long id;
String title;
String content;
long modifiedDate;
int type;
int pinned;
int locked;
int isPublic;
Note(long id, String title, String content, long modifiedDate, int type, int pinned, int locked, int isPublic) {
this.id = id;
this.title = title;
this.content = content;
this.modifiedDate = modifiedDate;
this.type = type;
this.pinned = pinned;
this.locked = locked;
this.isPublic = isPublic;
}
}
/**
* 便
*/
private static class NoteAdapter extends BaseAdapter {
private Activity mActivity;
private List<Note> mNoteList;
private LayoutInflater mInflater;
NoteAdapter(Activity activity, List<Note> noteList) {
mActivity = activity;
mNoteList = noteList;
mInflater = LayoutInflater.from(activity);
}
@Override
public int getCount() {
return mNoteList.size();
}
@Override
public Object getItem(int position) {
return mNoteList.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.note_item, parent, false);
holder = new ViewHolder();
holder.titleTextView = convertView.findViewById(R.id.tv_title);
holder.modifiedDateTextView = convertView.findViewById(R.id.tv_time);
holder.pinnedImageView = convertView.findViewById(R.id.iv_alert_icon);
holder.lockedImageView = convertView.findViewById(R.id.iv_lock_icon);
holder.publicImageView = convertView.findViewById(R.id.iv_public_icon);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
Note note = mNoteList.get(position);
// 显示标题,如果标题为空则显示内容摘要
String displayText;
if (note.title != null && !note.title.isEmpty()) {
displayText = note.title;
} else {
displayText = note.content;
}
holder.titleTextView.setText(displayText);
holder.modifiedDateTextView.setText(android.text.format.DateUtils.formatDateTime(
mActivity, note.modifiedDate,
android.text.format.DateUtils.FORMAT_SHOW_DATE |
android.text.format.DateUtils.FORMAT_NUMERIC_DATE |
android.text.format.DateUtils.FORMAT_SHOW_TIME));
// 设置置顶图标
holder.pinnedImageView.setVisibility(note.pinned == 1 ? View.VISIBLE : View.GONE);
// 设置锁定图标
holder.lockedImageView.setVisibility(note.locked == 1 ? View.VISIBLE : View.GONE);
// 设置公开图标
holder.publicImageView.setVisibility(note.isPublic == 1 ? View.VISIBLE : View.GONE);
return convertView;
}
private static class ViewHolder {
TextView titleTextView;
TextView modifiedDateTextView;
ImageView pinnedImageView;
ImageView lockedImageView;
ImageView publicImageView;
}
}
@Override
public boolean onOptionsItemSelected(android.view.MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
// 返回上一级活动
finish();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
}

@ -0,0 +1,321 @@
/*
* Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.micode.notes.ui;
import android.content.ContentValues;
import android.content.Intent;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import net.micode.notes.R;
import net.micode.notes.data.NotesDatabaseHelper;
import net.micode.notes.data.Users;
import net.micode.notes.tool.UserManager;
public class LoginActivity extends AppCompatActivity {
private EditText etUsername;
private EditText etPassword;
private NotesDatabaseHelper mDbHelper;
private SQLiteDatabase mDb;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
// 初始化数据库
mDbHelper = NotesDatabaseHelper.getInstance(this);
mDb = mDbHelper.getWritableDatabase();
// 初始化控件
etUsername = findViewById(R.id.et_username);
etPassword = findViewById(R.id.et_password);
}
/**
*
*/
public void onLoginClick(View view) {
String username = etUsername.getText().toString().trim();
String password = etPassword.getText().toString().trim();
// 验证输入
if (username.isEmpty() || password.isEmpty()) {
Toast.makeText(this, "用户名和密码不能为空", Toast.LENGTH_SHORT).show();
return;
}
// 验证用户名和密码
long userId = validateUser(username, password);
if (userId != -1) {
// 登录成功,保存用户信息
UserManager userManager = UserManager.getInstance(this);
userManager.saveCurrentUser(userId, username);
// 跳转到便签列表
Intent intent = new Intent(this, NotesListActivity.class);
startActivity(intent);
finish();
} else {
// 登录失败,提示错误
Toast.makeText(this, "用户名或密码错误", Toast.LENGTH_SHORT).show();
}
}
/**
*
*/
public void onRegisterClick(View view) {
showRegisterDialog();
}
/**
*
*/
public void onChangePasswordClick(View view) {
showChangePasswordDialog();
}
/**
*
*/
private void showRegisterDialog() {
View dialogView = getLayoutInflater().inflate(R.layout.dialog_register, null);
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setView(dialogView);
final AlertDialog dialog = builder.create();
// 初始化注册对话框控件
final EditText etRegisterUsername = dialogView.findViewById(R.id.et_register_username);
final EditText etRegisterPassword = dialogView.findViewById(R.id.et_register_password);
final EditText etRegisterConfirmPassword = dialogView.findViewById(R.id.et_register_confirm_password);
Button btnRegisterCancel = dialogView.findViewById(R.id.btn_register_cancel);
Button btnRegisterConfirm = dialogView.findViewById(R.id.btn_register_confirm);
// 取消按钮点击事件
btnRegisterCancel.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dialog.dismiss();
}
});
// 注册按钮点击事件
btnRegisterConfirm.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String username = etRegisterUsername.getText().toString().trim();
String password = etRegisterPassword.getText().toString().trim();
String confirmPassword = etRegisterConfirmPassword.getText().toString().trim();
// 验证输入
if (username.isEmpty() || password.isEmpty() || confirmPassword.isEmpty()) {
Toast.makeText(LoginActivity.this, "请填写完整信息", Toast.LENGTH_SHORT).show();
return;
}
if (!password.equals(confirmPassword)) {
Toast.makeText(LoginActivity.this, "两次输入的密码不一致", Toast.LENGTH_SHORT).show();
return;
}
// 检查用户名是否已存在
if (isUsernameExists(username)) {
Toast.makeText(LoginActivity.this, "用户名已存在", Toast.LENGTH_SHORT).show();
return;
}
// 注册用户
if (registerUser(username, password)) {
Toast.makeText(LoginActivity.this, "注册成功", Toast.LENGTH_SHORT).show();
dialog.dismiss();
} else {
Toast.makeText(LoginActivity.this, "注册失败,请重试", Toast.LENGTH_SHORT).show();
}
}
});
dialog.show();
}
/**
*
*/
private void showChangePasswordDialog() {
View dialogView = getLayoutInflater().inflate(R.layout.dialog_change_password, null);
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setView(dialogView);
final AlertDialog dialog = builder.create();
// 初始化修改密码对话框控件
final EditText etChangeUsername = dialogView.findViewById(R.id.et_change_username);
final EditText etCurrentPassword = dialogView.findViewById(R.id.et_current_password);
final EditText etNewPassword = dialogView.findViewById(R.id.et_new_password);
final EditText etConfirmNewPassword = dialogView.findViewById(R.id.et_confirm_new_password);
Button btnChangeCancel = dialogView.findViewById(R.id.btn_change_cancel);
Button btnChangeConfirm = dialogView.findViewById(R.id.btn_change_confirm);
// 取消按钮点击事件
btnChangeCancel.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dialog.dismiss();
}
});
// 确认修改按钮点击事件
btnChangeConfirm.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String username = etChangeUsername.getText().toString().trim();
String currentPassword = etCurrentPassword.getText().toString().trim();
String newPassword = etNewPassword.getText().toString().trim();
String confirmNewPassword = etConfirmNewPassword.getText().toString().trim();
// 验证输入
if (username.isEmpty() || currentPassword.isEmpty() || newPassword.isEmpty() || confirmNewPassword.isEmpty()) {
Toast.makeText(LoginActivity.this, "请填写完整信息", Toast.LENGTH_SHORT).show();
return;
}
if (!newPassword.equals(confirmNewPassword)) {
Toast.makeText(LoginActivity.this, "两次输入的新密码不一致", Toast.LENGTH_SHORT).show();
return;
}
// 验证当前密码
if (validateUser(username, currentPassword) == -1) {
Toast.makeText(LoginActivity.this, "用户名或当前密码错误", Toast.LENGTH_SHORT).show();
return;
}
// 修改密码
if (changePassword(username, newPassword)) {
Toast.makeText(LoginActivity.this, "密码修改成功", Toast.LENGTH_SHORT).show();
dialog.dismiss();
} else {
Toast.makeText(LoginActivity.this, "密码修改失败,请重试", Toast.LENGTH_SHORT).show();
}
}
});
dialog.show();
}
/**
* ID
*/
private long validateUser(String username, String password) {
String[] projection = {Users.UserColumns.ID};
String selection = Users.UserColumns.USERNAME + " = ? AND " + Users.UserColumns.PASSWORD + " = ?";
String[] selectionArgs = {username, password};
Cursor cursor = mDb.query(
NotesDatabaseHelper.TABLE.USER,
projection,
selection,
selectionArgs,
null,
null,
null
);
long userId = -1;
if (cursor.moveToFirst()) {
userId = cursor.getLong(cursor.getColumnIndexOrThrow(Users.UserColumns.ID));
}
cursor.close();
return userId;
}
/**
*
*/
private boolean isUsernameExists(String username) {
String[] projection = {Users.UserColumns.ID};
String selection = Users.UserColumns.USERNAME + " = ?";
String[] selectionArgs = {username};
Cursor cursor = mDb.query(
NotesDatabaseHelper.TABLE.USER,
projection,
selection,
selectionArgs,
null,
null,
null
);
boolean exists = cursor.getCount() > 0;
cursor.close();
return exists;
}
/**
*
*/
private boolean registerUser(String username, String password) {
ContentValues values = new ContentValues();
values.put(Users.UserColumns.USERNAME, username);
values.put(Users.UserColumns.PASSWORD, password);
long result = mDb.insert(NotesDatabaseHelper.TABLE.USER, null, values);
return result != -1;
}
/**
*
*/
private boolean changePassword(String username, String newPassword) {
ContentValues values = new ContentValues();
values.put(Users.UserColumns.PASSWORD, newPassword);
values.put(Users.UserColumns.MODIFIED_DATE, System.currentTimeMillis());
String selection = Users.UserColumns.USERNAME + " = ?";
String[] selectionArgs = {username};
int result = mDb.update(
NotesDatabaseHelper.TABLE.USER,
values,
selection,
selectionArgs
);
return result > 0;
}
@Override
protected void onDestroy() {
super.onDestroy();
// 关闭数据库连接
if (mDb != null && mDb.isOpen()) {
mDb.close();
}
}
}

@ -0,0 +1,56 @@
package net.micode.notes.ui;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.widget.LinearLayout;
import net.micode.notes.R;
public class SplashActivity extends Activity {
private static final int SPLASH_DISPLAY_DURATION = 2000; // 2秒
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash);
// 找到小米logo容器
LinearLayout miLogo = findViewById(R.id.mi_logo);
// 创建淡入淡出动画
AlphaAnimation animation = new AlphaAnimation(0.0f, 1.0f);
animation.setDuration(1500); // 1.5秒
animation.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
// 动画开始时的回调
}
@Override
public void onAnimationEnd(Animation animation) {
// 动画结束后跳转到主界面
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
Intent mainIntent = new Intent(SplashActivity.this, NotesListActivity.class);
SplashActivity.this.startActivity(mainIntent);
SplashActivity.this.finish();
}
}, 500); // 延迟500毫秒后跳转
}
@Override
public void onAnimationRepeat(Animation animation) {
// 动画重复时的回调
}
});
// 应用动画到小米logo
miLogo.startAnimation(animation);
}
}
Loading…
Cancel
Save