删除重复代码

pull/19/head
蒋天翔 1 month ago
parent d353c4a579
commit 75cb7ec7fd

@ -42,7 +42,7 @@
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/app_name"
android:launchMode="singleTop"
android:theme="@android:style/Theme.Holo.Light"
android:theme="@style/Theme.Notesmaster"
android:uiOptions="splitActionBarWhenNarrow"
android:windowSoftInputMode="adjustPan"
android:exported="true">
@ -60,7 +60,7 @@
android:name=".ui.NoteEditActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:launchMode="singleTop"
android:theme="@style/NoteTheme"
android:theme="@style/Theme.Notesmaster.Edit"
android:exported="true">
<!-- 意图过滤器:允许查看笔记 -->

@ -1,28 +1,39 @@
package net.micode.notes;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
import androidx.drawerlayout.widget.DrawerLayout;
import net.micode.notes.data.Notes;
import net.micode.notes.ui.SidebarFragment;
/**
*
* <p>
*
*
*
* </p>
*/
public class MainActivity extends AppCompatActivity {
public class MainActivity extends AppCompatActivity implements SidebarFragment.OnSidebarItemSelectedListener {
private static final String TAG = "MainActivity";
private DrawerLayout drawerLayout;
/**
*
* <p>
*
* </p>
*
*
* @param savedInstanceState
*/
@Override
@ -31,13 +42,118 @@ public class MainActivity extends AppCompatActivity {
// 启用边到边显示模式
EdgeToEdge.enable(this);
setContentView(R.layout.activity_main);
// 初始化DrawerLayout
drawerLayout = findViewById(R.id.drawer_layout);
if (drawerLayout != null) {
// 设置侧栏在左侧
drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED, Gravity.LEFT);
// 设置监听器:侧栏关闭时更新状态
drawerLayout.addDrawerListener(new DrawerLayout.DrawerListener() {
@Override
public void onDrawerSlide(View drawerView, float slideOffset) {
// 侧栏滑动时
}
@Override
public void onDrawerOpened(View drawerView) {
// 侧栏打开时
}
@Override
public void onDrawerClosed(View drawerView) {
// 侧栏关闭时
}
@Override
public void onDrawerStateChanged(int newState) {
// 侧栏状态改变时
}
});
}
// 设置窗口边距监听器,自动适配系统栏
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main_content), (v, insets) -> {
// 获取系统栏边距
Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
// 设置视图内边距以适配系统栏
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
return insets;
});
// 启动NotesListActivity作为主界面
Intent intent = new Intent(this, net.micode.notes.ui.NotesListActivity.class);
startActivity(intent);
}
// ==================== SidebarFragment.OnSidebarItemSelectedListener 实现 ====================
@Override
public void onFolderSelected(long folderId) {
Log.d(TAG, "Folder selected: " + folderId);
// 打开侧栏中的文件夹:不关闭侧栏,直接切换视图
// 这个回调通常用于侧栏中的文件夹项双击
// 实际跳转逻辑应该在NotesListActivity中处理
closeSidebar();
}
@Override
public void onTrashSelected() {
Log.d(TAG, "Trash selected");
// TODO: 实现跳转到回收站
// 关闭侧栏
closeSidebar();
}
@Override
public void onSyncSelected() {
Log.d(TAG, "Sync selected");
// TODO: 实现同步功能
}
@Override
public void onLoginSelected() {
Log.d(TAG, "Login selected");
// TODO: 实现登录功能
}
@Override
public void onExportSelected() {
Log.d(TAG, "Export selected");
// TODO: 实现导出功能
}
@Override
public void onSettingsSelected() {
Log.d(TAG, "Settings selected");
// 打开设置界面
Intent intent = new Intent(this, net.micode.notes.ui.NotesPreferenceActivity.class);
startActivity(intent);
// 关闭侧栏
closeSidebar();
}
@Override
public void onCreateFolder() {
Log.d(TAG, "Create folder");
// 创建文件夹功能由SidebarFragment内部处理
// 这里不需要做任何事情
}
@Override
public void onCloseSidebar() {
closeSidebar();
}
// ==================== 私有方法 ====================
/**
*
*/
private void closeSidebar() {
if (drawerLayout != null) {
drawerLayout.closeDrawer(Gravity.LEFT);
}
}
}

@ -235,6 +235,12 @@ public class Notes {
* <P> Type : INTEGER (long) </P>
*/
public static final String VERSION = "version";
/**
* Sign to indicate the note is pinned to top or not
* <P> Type : INTEGER </P>
*/
public static final String TOP = "top";
}
public interface DataColumns {

@ -66,11 +66,11 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
/**
*
* <p>
* 4
* 5
* onUpgrade
* </p>
*/
private static final int DB_VERSION = 4;
private static final int DB_VERSION = 5;
/**
*
@ -471,7 +471,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
* @param context
* @return NotesDatabaseHelper
*/
static synchronized NotesDatabaseHelper getInstance(Context context) {
public static synchronized NotesDatabaseHelper getInstance(Context context) {
if (mInstance == null) {
mInstance = new NotesDatabaseHelper(context);
}
@ -595,4 +595,17 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.VERSION
+ " INTEGER NOT NULL DEFAULT 0");
}
/**
* V5
* <p>
* TOPnote
* </p>
*
* @param db SQLiteDatabase
*/
private void upgradeToV5(SQLiteDatabase db) {
db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.TOP
+ " INTEGER NOT NULL DEFAULT 0");
}
}

@ -29,7 +29,7 @@ import android.util.Log;
import net.micode.notes.data.Notes;
import net.micode.notes.data.Notes.CallNote;
import net.micode.notes.data.Notes.NoteColumns;
import net.micode.notes.ui.NotesRecyclerViewAdapter.AppWidgetAttribute;
import net.micode.notes.ui.NotesListAdapter.AppWidgetAttribute;
import java.util.ArrayList;
import java.util.HashSet;

@ -1,68 +0,0 @@
/*
* 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.graphics.Rect;
import android.view.View;
import androidx.recyclerview.widget.RecyclerView;
/**
*
* <p>
* RecyclerView
*
* </p>
*/
public class GridSpacingItemDecoration extends RecyclerView.ItemDecoration {
private int spanCount;
private int spacing;
private boolean includeEdge;
/**
*
* @param spanCount
* @param spacing
* @param includeEdge
*/
public GridSpacingItemDecoration(int spanCount, int spacing, boolean includeEdge) {
this.spanCount = spanCount;
this.spacing = spacing;
this.includeEdge = includeEdge;
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
int position = parent.getChildAdapterPosition(view);
int column = position % spanCount;
if (includeEdge) {
outRect.left = spacing - column * spacing / spanCount;
outRect.right = (column + 1) * spacing / spanCount;
if (position < spanCount) {
outRect.top = spacing;
}
outRect.bottom = spacing;
} else {
outRect.left = column * spacing / spanCount;
outRect.right = spacing - (column + 1) * spacing / spanCount;
if (position >= spanCount) {
outRect.top = spacing;
}
}
}
}

@ -1,294 +0,0 @@
/*
* 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.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.util.Log;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.StaggeredGridLayoutManager;
/**
*
* <p>
* RecyclerView
* 线
*
* </p>
*/
public class LayoutManagerController {
private static final String TAG = "LayoutManagerController";
private static final String PREF_LAYOUT_TYPE = "layout_type";
private static final String PREF_GRID_SPAN_COUNT = "grid_span_count";
private static final String PREF_ITEM_SPACING = "item_spacing";
private Context mContext;
private RecyclerView mRecyclerView;
private RecyclerView.LayoutManager mCurrentLayoutManager;
private LayoutType mCurrentLayoutType;
private SharedPreferences mPreferences;
private LayoutChangeListener mListener;
/**
*
*/
public interface LayoutChangeListener {
void onLayoutChanged(LayoutType newLayoutType);
void onLayoutChangeFailed(Exception e);
}
/**
*
* @param context
* @param recyclerView RecyclerView
* @param listener
*/
public LayoutManagerController(Context context, RecyclerView recyclerView, LayoutChangeListener listener) {
mContext = context;
mRecyclerView = recyclerView;
mListener = listener;
mPreferences = PreferenceManager.getDefaultSharedPreferences(context);
// 加载保存的布局类型
String savedLayoutKey = mPreferences.getString(PREF_LAYOUT_TYPE, LayoutType.LINEAR.getKey());
mCurrentLayoutType = LayoutType.fromKey(savedLayoutKey);
Log.d(TAG, "LayoutManagerController initialized with layout: " + mCurrentLayoutType.getDisplayName());
}
/**
*
*/
public void initializeLayout() {
switchLayout(mCurrentLayoutType, false);
}
/**
*
* @param layoutType
* @param animate
* @return
*/
public boolean switchLayout(LayoutType layoutType, boolean animate) {
if (layoutType == mCurrentLayoutType) {
Log.d(TAG, "Already in " + layoutType.getDisplayName() + " mode");
return true;
}
long startTime = System.currentTimeMillis();
try {
// 保存滚动位置
int scrollPosition = 0;
if (mRecyclerView.getLayoutManager() != null) {
if (mRecyclerView.getLayoutManager() instanceof LinearLayoutManager) {
LinearLayoutManager layoutManager = (LinearLayoutManager) mRecyclerView.getLayoutManager();
scrollPosition = layoutManager.findFirstVisibleItemPosition();
} else if (mRecyclerView.getLayoutManager() instanceof GridLayoutManager) {
GridLayoutManager layoutManager = (GridLayoutManager) mRecyclerView.getLayoutManager();
scrollPosition = layoutManager.findFirstVisibleItemPosition();
} else if (mRecyclerView.getLayoutManager() instanceof StaggeredGridLayoutManager) {
StaggeredGridLayoutManager layoutManager = (StaggeredGridLayoutManager) mRecyclerView.getLayoutManager();
int[] positions = layoutManager.findFirstVisibleItemPositions(null);
scrollPosition = positions.length > 0 ? positions[0] : 0;
}
}
// 移除所有装饰
int decorationCount = mRecyclerView.getItemDecorationCount();
for (int i = decorationCount - 1; i >= 0; i--) {
mRecyclerView.removeItemDecorationAt(i);
}
// 创建新的布局管理器
RecyclerView.LayoutManager newLayoutManager = createLayoutManager(layoutType);
// 应用新布局
if (animate) {
mRecyclerView.setLayoutManager(newLayoutManager);
} else {
mRecyclerView.setLayoutManager(newLayoutManager);
}
// 添加间距装饰
addItemDecoration(layoutType);
// 保存布局偏好
saveLayoutPreference(layoutType);
// 恢复滚动位置
restoreScrollPosition(scrollPosition);
mCurrentLayoutManager = newLayoutManager;
mCurrentLayoutType = layoutType;
long duration = System.currentTimeMillis() - startTime;
Log.d(TAG, "Layout switched to " + layoutType.getDisplayName() + " in " + duration + "ms");
// 通知监听器
if (mListener != null) {
mListener.onLayoutChanged(layoutType);
}
return true;
} catch (Exception e) {
Log.e(TAG, "Failed to switch layout: " + e.getMessage(), e);
// 通知监听器失败
if (mListener != null) {
mListener.onLayoutChangeFailed(e);
}
return false;
}
}
/**
*
* @param layoutType
* @return
*/
private RecyclerView.LayoutManager createLayoutManager(LayoutType layoutType) {
int spanCount = getGridSpanCount();
switch (layoutType) {
case LINEAR:
return new LinearLayoutManager(mContext);
case GRID:
return new GridLayoutManager(mContext, spanCount);
case STAGGERED:
return new StaggeredGridLayoutManager(spanCount, StaggeredGridLayoutManager.VERTICAL);
default:
return new LinearLayoutManager(mContext);
}
}
/**
*
* @param layoutType
*/
private void addItemDecoration(LayoutType layoutType) {
int spacing = getItemSpacing();
switch (layoutType) {
case LINEAR:
mRecyclerView.addItemDecoration(new NoteItemDecoration(mContext));
break;
case GRID:
mRecyclerView.addItemDecoration(new GridSpacingItemDecoration(getGridSpanCount(), spacing, true));
break;
case STAGGERED:
mRecyclerView.addItemDecoration(new StaggeredGridSpacingItemDecoration(getGridSpanCount(), spacing, true));
break;
}
}
/**
*
* @param position
*/
private void restoreScrollPosition(int position) {
if (mRecyclerView.getAdapter() != null && position >= 0 && position < mRecyclerView.getAdapter().getItemCount()) {
mRecyclerView.scrollToPosition(position);
}
}
/**
*
* @param layoutType
*/
private void saveLayoutPreference(LayoutType layoutType) {
mPreferences.edit()
.putString(PREF_LAYOUT_TYPE, layoutType.getKey())
.apply();
}
/**
*
* @return
*/
public int getGridSpanCount() {
return mPreferences.getInt(PREF_GRID_SPAN_COUNT, 2);
}
/**
*
* @param spanCount
*/
public void setGridSpanCount(int spanCount) {
if (spanCount < 1) spanCount = 1;
if (spanCount > 4) spanCount = 4;
mPreferences.edit()
.putInt(PREF_GRID_SPAN_COUNT, spanCount)
.apply();
// 重新应用布局
switchLayout(mCurrentLayoutType, true);
}
/**
*
* @return
*/
public int getItemSpacing() {
return mPreferences.getInt(PREF_ITEM_SPACING, 16);
}
/**
*
* @param spacing
*/
public void setItemSpacing(int spacing) {
if (spacing < 0) spacing = 0;
if (spacing > 48) spacing = 48;
mPreferences.edit()
.putInt(PREF_ITEM_SPACING, spacing)
.apply();
// 重新应用布局
switchLayout(mCurrentLayoutType, true);
}
/**
*
* @return
*/
public LayoutType getCurrentLayoutType() {
return mCurrentLayoutType;
}
/**
*
* @return
*/
public LayoutType getNextLayoutType() {
LayoutType[] types = LayoutType.values();
int currentIndex = 0;
for (int i = 0; i < types.length; i++) {
if (types[i] == mCurrentLayoutType) {
currentIndex = i;
break;
}
}
return types[(currentIndex + 1) % types.length];
}
}

@ -1,199 +0,0 @@
/*
* 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.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.SeekBar;
import android.widget.Spinner;
import android.widget.TextView;
import net.micode.notes.R;
/**
*
* <p>
*
*
* </p>
*/
public class LayoutSettingsDialog {
private Context mContext;
private LayoutManagerController mLayoutManagerController;
private AlertDialog mDialog;
private Spinner mLayoutTypeSpinner;
private SeekBar mGridColumnsSeekBar;
private SeekBar mItemSpacingSeekBar;
private TextView mGridColumnsValue;
private TextView mItemSpacingValue;
/**
*
* @param context
* @param layoutManagerController
*/
public LayoutSettingsDialog(Context context, LayoutManagerController layoutManagerController) {
mContext = context;
mLayoutManagerController = layoutManagerController;
}
/**
*
*/
public void show() {
AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
builder.setTitle(R.string.layout_settings_title);
View dialogView = LayoutInflater.from(mContext).inflate(R.layout.layout_settings_dialog, null);
builder.setView(dialogView);
initViews(dialogView);
setupListeners();
builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
saveSettings();
}
});
builder.setNegativeButton(android.R.string.cancel, null);
mDialog = builder.create();
mDialog.show();
}
/**
*
* @param dialogView
*/
private void initViews(View dialogView) {
mLayoutTypeSpinner = (Spinner) dialogView.findViewById(R.id.layout_type_spinner);
mGridColumnsSeekBar = (SeekBar) dialogView.findViewById(R.id.grid_columns_seekbar);
mItemSpacingSeekBar = (SeekBar) dialogView.findViewById(R.id.item_spacing_seekbar);
mGridColumnsValue = (TextView) dialogView.findViewById(R.id.grid_columns_value);
mItemSpacingValue = (TextView) dialogView.findViewById(R.id.item_spacing_value);
// 设置布局类型选项
ArrayAdapter<LayoutType> layoutAdapter = new ArrayAdapter<>(
mContext, android.R.layout.simple_spinner_item, LayoutType.values());
mLayoutTypeSpinner.setAdapter(layoutAdapter);
// 设置当前值
LayoutType currentLayout = mLayoutManagerController.getCurrentLayoutType();
mLayoutTypeSpinner.setSelection(currentLayout.ordinal());
int gridColumns = mLayoutManagerController.getGridSpanCount();
mGridColumnsSeekBar.setProgress(gridColumns - 1);
mGridColumnsValue.setText(String.valueOf(gridColumns));
int itemSpacing = mLayoutManagerController.getItemSpacing();
mItemSpacingSeekBar.setProgress(itemSpacing / 2);
mItemSpacingValue.setText(String.valueOf(itemSpacing));
// 根据布局类型启用/禁用控件
updateControlStates(currentLayout);
}
/**
*
*/
private void setupListeners() {
mLayoutTypeSpinner.setOnItemSelectedListener(new android.widget.AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(android.widget.AdapterView<?> parent, View view, int position, long id) {
LayoutType selectedLayout = (LayoutType) parent.getItemAtPosition(position);
updateControlStates(selectedLayout);
}
@Override
public void onNothingSelected(android.widget.AdapterView<?> parent) {
}
});
mGridColumnsSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
int columns = progress + 1;
mGridColumnsValue.setText(String.valueOf(columns));
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
mItemSpacingSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
int spacing = progress * 2;
mItemSpacingValue.setText(String.valueOf(spacing));
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
}
/**
*
* @param layoutType
*/
private void updateControlStates(LayoutType layoutType) {
switch (layoutType) {
case LINEAR:
mGridColumnsSeekBar.setEnabled(false);
mItemSpacingSeekBar.setEnabled(false);
break;
case GRID:
case STAGGERED:
mGridColumnsSeekBar.setEnabled(true);
mItemSpacingSeekBar.setEnabled(true);
break;
}
}
/**
*
*/
private void saveSettings() {
LayoutType selectedLayout = (LayoutType) mLayoutTypeSpinner.getSelectedItem();
int gridColumns = mGridColumnsSeekBar.getProgress() + 1;
int itemSpacing = mItemSpacingSeekBar.getProgress() * 2;
mLayoutManagerController.setGridSpanCount(gridColumns);
mLayoutManagerController.setItemSpacing(itemSpacing);
if (selectedLayout != mLayoutManagerController.getCurrentLayoutType()) {
mLayoutManagerController.switchLayout(selectedLayout, true);
}
mDialog.dismiss();
}
}

@ -1,61 +0,0 @@
/*
* 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;
/**
*
* <p>
* 线
*
* </p>
*/
public enum LayoutType {
LINEAR("linear", "列表布局", "传统的垂直列表布局,适合大量笔记浏览"),
GRID("grid", "网格布局", "网格排列布局,适合快速浏览和预览"),
STAGGERED("staggered", "瀑布流布局", "错落有致的布局,适合不同长度的笔记展示");
private final String key;
private final String displayName;
private final String description;
LayoutType(String key, String displayName, String description) {
this.key = key;
this.displayName = displayName;
this.description = description;
}
public String getKey() {
return key;
}
public String getDisplayName() {
return displayName;
}
public String getDescription() {
return description;
}
public static LayoutType fromKey(String key) {
for (LayoutType type : values()) {
if (type.key.equals(key)) {
return type;
}
}
return LINEAR;
}
}

@ -71,8 +71,11 @@ import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import androidx.appcompat.app.AppCompatActivity;
import com.google.android.material.appbar.MaterialToolbar;
public class NoteEditActivity extends Activity implements OnClickListener,
public class NoteEditActivity extends AppCompatActivity implements OnClickListener,
NoteSettingChangedListener, OnTextViewChangeListener {
/**
*
@ -143,6 +146,8 @@ public class NoteEditActivity extends Activity implements OnClickListener,
private SharedPreferences mSharedPrefs;
private int mFontSizeId;
private MaterialToolbar toolbar;
private static final String PREFERENCE_FONT_SIZE = "pref_font_size";
private static final int SHORTCUT_ICON_TITLE_MAX_LEN = 10;
@ -160,6 +165,15 @@ public class NoteEditActivity extends Activity implements OnClickListener,
super.onCreate(savedInstanceState);
this.setContentView(R.layout.note_edit);
// 初始化Toolbar使用MaterialToolbar与列表页面一致
MaterialToolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
}
toolbar.setNavigationOnClickListener(v -> finish());
if (savedInstanceState == null && !initActivityState(getIntent())) {
finish();
return;
@ -284,6 +298,49 @@ public class NoteEditActivity extends Activity implements OnClickListener,
return true;
}
/**
*
* <p>
* UI
* </p>
*/
private void initResources() {
mHeadViewPanel = findViewById(R.id.note_title);
mNoteHeaderHolder = new HeadViewHolder();
mNoteHeaderHolder.tvModified = findViewById(R.id.tv_modified_date);
mNoteHeaderHolder.ivAlertIcon = findViewById(R.id.iv_alert_icon);
mNoteHeaderHolder.tvAlertDate = findViewById(R.id.tv_alert_date);
mNoteHeaderHolder.ibSetBgColor = findViewById(R.id.btn_set_bg_color);
mNoteHeaderHolder.ibSetBgColor.setOnClickListener(this);
mNoteEditor = findViewById(R.id.note_edit_view);
mNoteEditorPanel = findViewById(R.id.sv_note_edit);
mNoteBgColorSelector = findViewById(R.id.note_bg_color_selector);
// 设置背景颜色选择器的点击事件
for (int id : sBgSelectorBtnsMap.keySet()) {
ImageView iv = findViewById(id);
iv.setOnClickListener(this);
}
mFontSizeSelector = findViewById(R.id.font_size_selector);
for (int id : sFontSizeBtnsMap.keySet()) {
View view = findViewById(id);
view.setOnClickListener(this);
}
mSharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
mFontSizeId = mSharedPrefs.getInt(PREFERENCE_FONT_SIZE, ResourceParser.BG_DEFAULT_FONT_SIZE);
/**
* HACKME: Fix bug of store the resource id in shared preference.
* The id may larger than the length of resources, in this case,
* return the {@link ResourceParser#BG_DEFAULT_FONT_SIZE}
*/
if (mFontSizeId >= TextAppearanceResources.getResourcesSize()) {
mFontSizeId = ResourceParser.BG_DEFAULT_FONT_SIZE;
}
mEditTextList = findViewById(R.id.note_edit_list);
}
@Override
protected void onResume() {
super.onResume();
@ -430,47 +487,6 @@ public class NoteEditActivity extends Activity implements OnClickListener,
return true;
}
/**
*
* <p>
* UI
* SharedPreferences
* </p>
*/
private void initResources() {
mHeadViewPanel = findViewById(R.id.note_title);
mNoteHeaderHolder = new HeadViewHolder();
mNoteHeaderHolder.tvModified = (TextView) findViewById(R.id.tv_modified_date);
mNoteHeaderHolder.ivAlertIcon = (ImageView) findViewById(R.id.iv_alert_icon);
mNoteHeaderHolder.tvAlertDate = (TextView) findViewById(R.id.tv_alert_date);
mNoteHeaderHolder.ibSetBgColor = (ImageView) findViewById(R.id.btn_set_bg_color);
mNoteHeaderHolder.ibSetBgColor.setOnClickListener(this);
mNoteEditor = (EditText) findViewById(R.id.note_edit_view);
mNoteEditorPanel = findViewById(R.id.sv_note_edit);
mNoteBgColorSelector = findViewById(R.id.note_bg_color_selector);
for (int id : sBgSelectorBtnsMap.keySet()) {
ImageView iv = (ImageView) findViewById(id);
iv.setOnClickListener(this);
}
mFontSizeSelector = findViewById(R.id.font_size_selector);
for (int id : sFontSizeBtnsMap.keySet()) {
View view = findViewById(id);
view.setOnClickListener(this);
};
mSharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
mFontSizeId = mSharedPrefs.getInt(PREFERENCE_FONT_SIZE, ResourceParser.BG_DEFAULT_FONT_SIZE);
/**
* HACKME: Fix bug of store the resource id in shared preference.
* The id may larger than the length of resources, in this case,
* return the {@link ResourceParser#BG_DEFAULT_FONT_SIZE}
*/
if(mFontSizeId >= TextAppearanceResources.getResourcesSize()) {
mFontSizeId = ResourceParser.BG_DEFAULT_FONT_SIZE;
}
mEditTextList = (LinearLayout) findViewById(R.id.note_edit_list);
}
/**
*
* <p>
@ -528,7 +544,7 @@ public class NoteEditActivity extends Activity implements OnClickListener,
if (id == R.id.btn_set_bg_color) {
mNoteBgColorSelector.setVisibility(View.VISIBLE);
findViewById(sBgSelectorSelectionMap.get(mWorkingNote.getBgColorId())).setVisibility(
- View.VISIBLE);
View.VISIBLE);
} else if (sBgSelectorBtnsMap.containsKey(id)) {
findViewById(sBgSelectorSelectionMap.get(mWorkingNote.getBgColorId())).setVisibility(
View.GONE);

@ -59,6 +59,7 @@ public class NoteItemData {
NoteColumns.TYPE,
NoteColumns.WIDGET_ID,
NoteColumns.WIDGET_TYPE,
NoteColumns.TOP, // 新增TOP字段
};
// 列索引常量,用于从查询结果中获取对应列的数据
@ -74,6 +75,7 @@ public class NoteItemData {
private static final int TYPE_COLUMN = 9;
private static final int WIDGET_ID_COLUMN = 10;
private static final int WIDGET_TYPE_COLUMN = 11;
private static final int TOP_COLUMN = 12;
// 笔记ID
private long mId;
@ -99,6 +101,8 @@ public class NoteItemData {
private int mWidgetId;
// 桌面小部件类型
private int mWidgetType;
// 是否置顶
private boolean mIsPinned;
// 联系人名称(用于通话记录)
private String mName;
// 电话号码(用于通话记录)
@ -140,6 +144,12 @@ public class NoteItemData {
mType = cursor.getInt(TYPE_COLUMN);
mWidgetId = cursor.getInt(WIDGET_ID_COLUMN);
mWidgetType = cursor.getInt(WIDGET_TYPE_COLUMN);
// 读取置顶状态
if (cursor.getColumnCount() > TOP_COLUMN) {
mIsPinned = cursor.getInt(TOP_COLUMN) > 0;
} else {
mIsPinned = false;
}
mPhoneNumber = "";
// 如果是通话记录笔记,获取电话号码和联系人名称
@ -377,6 +387,14 @@ public class NoteItemData {
return (mAlertDate > 0);
}
/**
*
* @return true
*/
public boolean isPinned() {
return mIsPinned;
}
/**
*
*

@ -1,73 +0,0 @@
/*
* 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.Context;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.view.View;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.RecyclerView.ItemDecoration;
import net.micode.notes.R;
/**
*
* <p>
* RecyclerView线ListViewdivider
* </p>
*/
public class NoteItemDecoration extends ItemDecoration {
private Drawable mDivider;
private int mDividerHeight;
/**
*
* @param context
*/
public NoteItemDecoration(Context context) {
mDivider = context.getResources().getDrawable(R.drawable.list_divider);
if (mDivider != null) {
mDividerHeight = 1;
} else {
mDividerHeight = mDivider.getIntrinsicHeight();
}
}
@Override
public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
int left = parent.getPaddingLeft();
int right = parent.getWidth() - parent.getPaddingRight();
int childCount = parent.getChildCount();
for (int i = 0; i < childCount - 1; i++) {
View child = parent.getChildAt(i);
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
int top = child.getBottom() + params.bottomMargin;
int bottom = top + mDividerHeight;
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
outRect.bottom = mDividerHeight;
}
}

@ -1,54 +0,0 @@
/*
* 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.view.View;
import android.widget.CheckBox;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.recyclerview.widget.RecyclerView;
import net.micode.notes.R;
/**
* ViewHolder
* <p>
* RecyclerViewViewHolder
* findViewById
* </p>
*/
public class NoteViewHolder extends RecyclerView.ViewHolder {
public ImageView mAlert;
public TextView mTitle;
public TextView mTime;
public TextView mCallName;
public CheckBox mCheckBox;
/**
*
* @param itemView
*/
public NoteViewHolder(View itemView) {
super(itemView);
// 查找所有子视图(只执行一次)
mAlert = (ImageView) itemView.findViewById(R.id.iv_alert_icon);
mTitle = (TextView) itemView.findViewById(R.id.tv_title);
mTime = (TextView) itemView.findViewById(R.id.tv_time);
mCallName = (TextView) itemView.findViewById(R.id.tv_name);
mCheckBox = (CheckBox) itemView.findViewById(android.R.id.checkbox);
}
}

@ -1,465 +0,0 @@
/*
* 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.Context;
import android.database.Cursor;
import android.util.Log;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import androidx.recyclerview.widget.RecyclerView;
import net.micode.notes.R;
import net.micode.notes.data.Notes;
import net.micode.notes.tool.DataUtils;
import net.micode.notes.tool.ResourceParser.NoteItemBgResources;
import java.util.HashSet;
/**
* RecyclerView
*
* RecyclerView.AdapterRecyclerView
*
* NotesListAdapter使RecyclerView
*
*
* 1. NoteViewHolder
* 2.
* 3. ID
* 4.
* 5.
*
* @see NoteViewHolder
* @see NoteItemData
*/
public class NotesRecyclerViewAdapter extends RecyclerView.Adapter<NoteViewHolder> {
private static final String TAG = "NotesRecyclerViewAdapter";
private Context mContext;
private Cursor mCursor;
private SparseArray<Boolean> mSelectedIndex;
private int mNotesCount;
private boolean mChoiceMode;
private OnItemClickListener mOnItemClickListener;
private OnItemLongClickListener mOnItemLongClickListener;
/**
*
*
* ID
*/
public static class AppWidgetAttribute {
public int widgetId;
public int widgetType;
}
/**
*
*/
public interface OnItemClickListener {
void onItemClick(View view, int position, long id);
}
/**
*
*/
public interface OnItemLongClickListener {
boolean onItemLongClick(View view, int position, long id);
}
/**
*
*
* Map
*
* @param context null
*/
public NotesRecyclerViewAdapter(Context context) {
mSelectedIndex = new SparseArray<>();
mContext = context;
mNotesCount = 0;
}
/**
* ViewHolder
*
* @param parent
* @param viewType
* @return NoteViewHolder
*/
@Override
public NoteViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(mContext)
.inflate(R.layout.note_item, parent, false);
final NoteViewHolder holder = new NoteViewHolder(view);
// 设置点击监听
view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mOnItemClickListener != null) {
int position = holder.getAdapterPosition();
if (position != RecyclerView.NO_POSITION) {
long id = getItemId(position);
mOnItemClickListener.onItemClick(v, position, id);
}
}
}
});
// 设置长按监听
view.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
if (mOnItemLongClickListener != null) {
int position = holder.getAdapterPosition();
if (position != RecyclerView.NO_POSITION) {
long id = getItemId(position);
return mOnItemLongClickListener.onItemLongClick(v, position, id);
}
}
return false;
}
});
return holder;
}
/**
* ViewHolder
*
* ViewHolder
*
* @param holder ViewHolder
* @param position
*/
@Override
public void onBindViewHolder(NoteViewHolder holder, int position) {
if (mCursor != null && mCursor.moveToPosition(position)) {
NoteItemData itemData = new NoteItemData(mContext, mCursor);
// 绑定数据到视图
bindViewHolder(holder, itemData, position);
}
}
/**
* ViewHolder
*
* @param holder ViewHolder
* @param data
* @param position
*/
private void bindViewHolder(NoteViewHolder holder, NoteItemData data, int position) {
// 处理复选框
if (mChoiceMode && data.getType() == Notes.TYPE_NOTE) {
holder.mCheckBox.setVisibility(View.VISIBLE);
holder.mCheckBox.setChecked(isSelectedItem(position));
} else {
holder.mCheckBox.setVisibility(View.GONE);
}
// 处理提醒图标
if (data.hasAlert()) {
holder.mAlert.setImageResource(R.drawable.clock);
holder.mAlert.setVisibility(View.VISIBLE);
} else {
holder.mAlert.setVisibility(View.GONE);
}
// 处理标题
if (data.getId() == Notes.ID_CALL_RECORD_FOLDER) {
holder.mCallName.setVisibility(View.GONE);
holder.mAlert.setVisibility(View.VISIBLE);
holder.mTitle.setTextAppearance(mContext, R.style.TextAppearancePrimaryItem);
holder.mTitle.setText(mContext.getString(R.string.call_record_folder_name)
+ mContext.getString(R.string.format_folder_files_count, data.getNotesCount()));
holder.mAlert.setImageResource(R.drawable.call_record);
} else if (data.getParentId() == Notes.ID_CALL_RECORD_FOLDER) {
holder.mCallName.setVisibility(View.VISIBLE);
holder.mCallName.setText(data.getCallName());
holder.mTitle.setTextAppearance(mContext, R.style.TextAppearanceSecondaryItem);
holder.mTitle.setText(DataUtils.getFormattedSnippet(data.getSnippet()));
} else {
holder.mCallName.setVisibility(View.GONE);
holder.mTitle.setTextAppearance(mContext, R.style.TextAppearancePrimaryItem);
if (data.getType() == Notes.TYPE_FOLDER) {
holder.mTitle.setText(data.getSnippet()
+ mContext.getString(R.string.format_folder_files_count,
data.getNotesCount()));
holder.mAlert.setVisibility(View.GONE);
} else {
holder.mTitle.setText(DataUtils.getFormattedSnippet(data.getSnippet()));
if (data.hasAlert()) {
holder.mAlert.setImageResource(R.drawable.clock);
holder.mAlert.setVisibility(View.VISIBLE);
} else {
holder.mAlert.setVisibility(View.GONE);
}
}
}
// 设置时间
holder.mTime.setText(android.text.format.DateUtils.getRelativeTimeSpanString(data.getModifiedDate()));
// 设置背景
setBackground(holder.itemView, data);
}
/**
*
* @param view
* @param data
*/
private void setBackground(View view, NoteItemData data) {
int id = data.getBgColorId();
if (data.getType() == Notes.TYPE_NOTE) {
int bgRes;
if (data.isSingle() || data.isOneFollowingFolder()) {
bgRes = NoteItemBgResources.getNoteBgSingleRes(id);
} else if (data.isLast()) {
bgRes = NoteItemBgResources.getNoteBgLastRes(id);
} else if (data.isFirst() || data.isMultiFollowingFolder()) {
bgRes = NoteItemBgResources.getNoteBgFirstRes(id);
} else {
bgRes = NoteItemBgResources.getNoteBgNormalRes(id);
}
view.setBackgroundResource(bgRes);
} else {
view.setBackgroundResource(NoteItemBgResources.getFolderBgRes());
}
}
/**
*
*
* @return null0
*/
@Override
public int getItemCount() {
return mCursor != null ? mCursor.getCount() : 0;
}
/**
* ID
*
* @param position
* @return IDnull0
*/
public long getItemId(int position) {
if (mCursor != null && mCursor.moveToPosition(position)) {
return mCursor.getLong(mCursor.getColumnIndexOrThrow(Notes.NoteColumns.ID));
}
return 0;
}
/**
*
*
* @param position
* @return nullnull
*/
public Object getItem(int position) {
if (mCursor != null && mCursor.moveToPosition(position)) {
return mCursor;
}
return null;
}
/**
*
*
* @param position 0
* @param checked
*/
public void setCheckedItem(int position, boolean checked) {
mSelectedIndex.put(position, checked);
notifyItemChanged(position);
}
/**
*
*
* @return truefalse
*/
public boolean isInChoiceMode() {
return mChoiceMode;
}
/**
*
*
* @param mode truefalse退
*/
public void setChoiceMode(boolean mode) {
mSelectedIndex.clear();
mChoiceMode = mode;
notifyDataSetChanged();
}
/**
*
*
* @param checked truefalse
*/
public void selectAll(boolean checked) {
if (mCursor != null) {
for (int i = 0; i < getItemCount(); i++) {
if (mCursor.moveToPosition(i)) {
if (NoteItemData.getNoteType(mCursor) == Notes.TYPE_NOTE) {
mSelectedIndex.put(i, checked);
}
}
}
notifyDataSetChanged();
}
}
/**
* ID
*
* @return IDHashSet
*/
public HashSet<Long> getSelectedItemIds() {
HashSet<Long> itemSet = new HashSet<>();
for (int i = 0; i < mSelectedIndex.size(); i++) {
int key = mSelectedIndex.keyAt(i);
if (mSelectedIndex.get(key)) {
long id = getItemId(key);
if (id == Notes.ID_ROOT_FOLDER) {
Log.d(TAG, "Wrong item id, should not happen");
} else {
itemSet.add(id);
}
}
}
return itemSet;
}
/**
*
*
* @return HashSetnull
*/
public HashSet<AppWidgetAttribute> getSelectedWidget() {
HashSet<AppWidgetAttribute> itemSet = new HashSet<>();
for (int i = 0; i < mSelectedIndex.size(); i++) {
int key = mSelectedIndex.keyAt(i);
if (mSelectedIndex.get(key)) {
Cursor c = (Cursor) getItem(key);
if (c != null) {
AppWidgetAttribute widget = new AppWidgetAttribute();
NoteItemData item = new NoteItemData(mContext, c);
widget.widgetId = item.getWidgetId();
widget.widgetType = item.getWidgetType();
itemSet.add(widget);
} else {
Log.e(TAG, "Invalid cursor");
return null;
}
}
}
return itemSet;
}
/**
*
*
* @return 0
*/
public int getSelectedCount() {
int count = 0;
for (int i = 0; i < mSelectedIndex.size(); i++) {
if (mSelectedIndex.get(mSelectedIndex.keyAt(i))) {
count++;
}
}
return count;
}
/**
*
*
* @return truefalse
*/
public boolean isAllSelected() {
int checkedCount = getSelectedCount();
return (checkedCount != 0 && checkedCount == mNotesCount);
}
/**
*
*
* @param position 0
* @return truefalse
*/
public boolean isSelectedItem(int position) {
return mSelectedIndex.get(position, false);
}
/**
*
*
* @param newCursor
*/
public Cursor swapCursor(Cursor newCursor) {
Cursor oldCursor = mCursor;
mCursor = newCursor;
calcNotesCount();
notifyDataSetChanged();
return oldCursor;
}
/**
*
*/
private void calcNotesCount() {
mNotesCount = 0;
if (mCursor != null) {
for (int i = 0; i < getItemCount(); i++) {
if (mCursor.moveToPosition(i)) {
if (NoteItemData.getNoteType(mCursor) == Notes.TYPE_NOTE) {
mNotesCount++;
}
}
}
}
}
/**
*
*
* @param listener
*/
public void setOnItemClickListener(OnItemClickListener listener) {
mOnItemClickListener = listener;
}
/**
*
*
* @param listener
*/
public void setOnItemLongClickListener(OnItemLongClickListener listener) {
mOnItemLongClickListener = listener;
}
}

@ -1,70 +0,0 @@
/*
* 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.graphics.Rect;
import android.view.View;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.StaggeredGridLayoutManager;
/**
*
* <p>
* RecyclerView
*
* </p>
*/
public class StaggeredGridSpacingItemDecoration extends RecyclerView.ItemDecoration {
private int spanCount;
private int spacing;
private boolean includeEdge;
/**
*
* @param spanCount
* @param spacing
* @param includeEdge
*/
public StaggeredGridSpacingItemDecoration(int spanCount, int spacing, boolean includeEdge) {
this.spanCount = spanCount;
this.spacing = spacing;
this.includeEdge = includeEdge;
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
StaggeredGridLayoutManager.LayoutParams params =
(StaggeredGridLayoutManager.LayoutParams) view.getLayoutParams();
int spanIndex = params.getSpanIndex();
if (includeEdge) {
outRect.left = spacing - spanIndex * spacing / spanCount;
outRect.right = (spanIndex + 1) * spacing / spanCount;
if (params.getViewAdapterPosition() < spanCount) {
outRect.top = spacing;
}
outRect.bottom = spacing;
} else {
outRect.left = spanIndex * spacing / spanCount;
outRect.right = spacing - (spanIndex + 1) * spacing / spanCount;
if (params.getViewAdapterPosition() >= spanCount) {
outRect.top = spacing;
}
}
}
}

@ -1,20 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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.
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<size android:height="1dp" />
<solid android:color="#E0E0E0" />
</shape>

@ -1,19 +1,37 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.drawerlayout.widget.DrawerLayout 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:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
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
android:id="@+id/main_content"
android:layout_width="match_parent"
android:layout_height="match_parent">
</androidx.constraintlayout.widget.ConstraintLayout>
<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>
<!-- 侧栏 -->
<fragment
android:id="@+id/sidebar_fragment"
android:name="net.micode.notes.ui.SidebarFragment"
android:layout_width="280dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:tag="sidebar" />
</androidx.drawerlayout.widget.DrawerLayout>

@ -1,103 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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.
-->
<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:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/layout_linear"
android:textSize="16sp"
android:textStyle="bold"
android:layout_marginBottom="16dp" />
<Spinner
android:id="@+id/layout_type_spinner"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="24dp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical"
android:layout_marginBottom="16dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/layout_grid_columns"
android:textSize="14sp"
android:layout_marginEnd="16dp" />
<TextView
android:id="@+id/grid_columns_value"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="2"
android:textSize="18sp"
android:textStyle="bold"
android:minWidth="30dp"
android:gravity="center" />
<SeekBar
android:id="@+id/grid_columns_seekbar"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:max="3"
android:progress="1" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical"
android:layout_marginBottom="16dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/layout_item_spacing"
android:textSize="14sp"
android:layout_marginEnd="16dp" />
<TextView
android:id="@+id/item_spacing_value"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="16"
android:textSize="18sp"
android:textStyle="bold"
android:minWidth="30dp"
android:gravity="center" />
<SeekBar
android:id="@+id/item_spacing_seekbar"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:max="24"
android:progress="8" />
</LinearLayout>
</LinearLayout>

@ -1,45 +1,56 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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.
-->
<FrameLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@drawable/list_background"
android:fitsSystemWindows="true"
android:paddingTop="24dp"
xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 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.
-->
<!-- 统一使用Material风格与列表页面一致 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<!-- 统一使用MaterialToolbar与列表页面一致 -->
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:title="@string/menu_edit_note"
app:navigationIcon="@android:drawable/ic_menu_close_clear_cancel" />
<!-- 主内容区域 -->
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="vertical">
<LinearLayout
android:id="@+id/note_title"
android:layout_width="fill_parent"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/tv_modified_date"
android:layout_width="0dip"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_gravity="left|center_vertical"
android:layout_marginRight="8dip"
android:layout_marginRight="8dp"
android:textAppearance="@style/TextAppearanceSecondaryItem" />
<ImageView
@ -54,8 +65,8 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="2dip"
android:layout_marginRight="8dip"
android:layout_marginLeft="2dp"
android:layout_marginRight="8dp"
android:textAppearance="@style/TextAppearanceSecondaryItem" />
<ImageButton
@ -67,31 +78,32 @@
<LinearLayout
android:id="@+id/sv_note_edit"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="vertical">
<ImageView
android:layout_width="fill_parent"
android:layout_height="7dip"
android:layout_width="match_parent"
android:layout_height="7dp"
android:background="@drawable/bg_color_btn_mask" />
<ScrollView
android:layout_width="fill_parent"
android:layout_height="0dip"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:scrollbars="none"
android:overScrollMode="never"
android:layout_gravity="left|top"
android:fadingEdgeLength="0dip">
android:fadingEdgeLength="0dp">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent">
android:layout_width="match_parent"
android:layout_height="match_parent">
<net.micode.notes.ui.NoteEditText
android:id="@+id/note_edit_view"
android:layout_width="fill_parent"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="left|top"
android:background="@null"
@ -103,300 +115,302 @@
<LinearLayout
android:id="@+id/note_edit_list"
android:layout_width="fill_parent"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginLeft="-10dip"
android:layout_marginLeft="-10dp"
android:visibility="gone" />
</LinearLayout>
</ScrollView>
<ImageView
android:layout_width="fill_parent"
android:layout_height="7dip"
android:layout_width="match_parent"
android:layout_height="7dp"
android:background="@drawable/bg_color_btn_mask" />
</LinearLayout>
</LinearLayout>
<ImageView
android:id="@+id/btn_set_bg_color"
android:layout_height="43dip"
android:layout_width="wrap_content"
android:background="@drawable/bg_color_btn_mask"
android:layout_gravity="top|right" />
<ImageView
android:id="@+id/btn_set_bg_color"
android:layout_height="43dp"
android:layout_width="wrap_content"
android:background="@drawable/bg_color_btn_mask"
android:layout_gravity="top|right" />
<LinearLayout
android:id="@+id/note_bg_color_selector"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/note_edit_color_selector_panel"
android:layout_marginTop="30dip"
android:layout_marginRight="8dip"
android:layout_gravity="top|right"
android:visibility="gone">
<FrameLayout
android:layout_width="0dip"
android:layout_height="match_parent"
android:layout_weight="1">
<LinearLayout
android:id="@+id/note_bg_color_selector"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/note_edit_color_selector_panel"
android:layout_marginTop="30dp"
android:layout_marginRight="8dp"
android:layout_gravity="top|right"
android:visibility="gone">
<ImageView
android:id="@+id/iv_bg_yellow"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<FrameLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1">
<ImageView
android:id="@+id/iv_bg_yellow_select"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|right"
android:layout_marginRight="5dip"
android:focusable="false"
android:visibility="gone"
android:src="@drawable/selected" />
</FrameLayout>
<FrameLayout
android:layout_width="0dip"
android:layout_height="match_parent"
android:layout_weight="1">
<ImageView
android:id="@+id/iv_bg_yellow"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<ImageView
android:id="@+id/iv_bg_blue"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<ImageView
android:id="@+id/iv_bg_yellow_select"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|right"
android:layout_marginRight="5dp"
android:focusable="false"
android:visibility="gone"
android:src="@drawable/selected" />
</FrameLayout>
<FrameLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1">
<ImageView
android:id="@+id/iv_bg_blue_select"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|right"
android:focusable="false"
android:visibility="gone"
android:layout_marginRight="3dip"
android:src="@drawable/selected" />
</FrameLayout>
<FrameLayout
android:layout_width="0dip"
android:layout_height="match_parent"
android:layout_weight="1">
<ImageView
android:id="@+id/iv_bg_blue"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<ImageView
android:id="@+id/iv_bg_white"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<ImageView
android:id="@+id/iv_bg_blue_select"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|right"
android:focusable="false"
android:visibility="gone"
android:layout_marginRight="3dp"
android:src="@drawable/selected" />
</FrameLayout>
<FrameLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1">
<ImageView
android:id="@+id/iv_bg_white_select"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|right"
android:focusable="false"
android:visibility="gone"
android:layout_marginRight="2dip"
android:src="@drawable/selected" />
</FrameLayout>
<FrameLayout
android:layout_width="0dip"
android:layout_height="match_parent"
android:layout_weight="1">
<ImageView
android:id="@+id/iv_bg_white"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<ImageView
android:id="@+id/iv_bg_green"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<ImageView
android:id="@+id/iv_bg_white_select"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|right"
android:focusable="false"
android:visibility="gone"
android:layout_marginRight="2dp"
android:src="@drawable/selected" />
</FrameLayout>
<FrameLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1">
<ImageView
android:id="@+id/iv_bg_green_select"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|right"
android:focusable="false"
android:visibility="gone"
android:src="@drawable/selected" />
</FrameLayout>
<ImageView
android:id="@+id/iv_bg_green"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<FrameLayout
android:layout_width="0dip"
android:layout_height="match_parent"
android:layout_weight="1">
<ImageView
android:id="@+id/iv_bg_green_select"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|right"
android:focusable="false"
android:visibility="gone"
android:layout_marginRight="5dp"
android:src="@drawable/selected" />
</FrameLayout>
<FrameLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1">
<ImageView
android:id="@+id/iv_bg_red"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<ImageView
android:id="@+id/iv_bg_red"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<ImageView
android:id="@+id/iv_bg_red_select"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|right"
android:focusable="false"
android:visibility="gone"
android:src="@drawable/selected" />
</FrameLayout>
</LinearLayout>
<ImageView
android:id="@+id/iv_bg_red_select"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|right"
android:focusable="false"
android:visibility="gone"
android:layout_marginRight="3dp"
android:src="@drawable/selected" />
</FrameLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/font_size_selector"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="@drawable/font_size_selector_bg"
android:layout_gravity="bottom"
android:visibility="gone">
<FrameLayout
android:id="@+id/ll_font_small"
android:layout_width="0dip"
<LinearLayout
android:id="@+id/font_size_selector"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1">
android:background="@drawable/font_size_selector_bg"
android:layout_gravity="bottom"
android:visibility="gone">
<LinearLayout
android:layout_width="wrap_content"
<FrameLayout
android:id="@+id/ll_font_small"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_gravity="center"
android:gravity="center">
android:layout_weight="1">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/font_small"
android:layout_marginBottom="5dip" />
<TextView
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/menu_font_small"
android:textAppearance="@style/TextAppearanceUnderMenuIcon" />
</LinearLayout>
android:orientation="vertical"
android:layout_gravity="center"
android:gravity="center">
<ImageView
android:id="@+id/iv_small_select"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|right"
android:layout_marginRight="6dip"
android:layout_marginBottom="-7dip"
android:focusable="false"
android:visibility="gone"
android:src="@drawable/selected" />
</FrameLayout>
<FrameLayout
android:id="@+id/ll_font_normal"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/font_small"
android:layout_marginBottom="5dp" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_gravity="center"
android:gravity="center">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/menu_font_small"
android:textAppearance="@style/TextAppearanceUnderMenuIcon" />
</LinearLayout>
<ImageView
android:id="@+id/iv_small_select"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/font_normal"
android:layout_marginBottom="5dip" />
android:layout_gravity="bottom|right"
android:layout_marginRight="6dp"
android:layout_marginBottom="-7dp"
android:focusable="false"
android:visibility="gone"
android:src="@drawable/selected" />
</FrameLayout>
<FrameLayout
android:id="@+id/ll_font_normal"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1">
<TextView
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/menu_font_normal"
android:textAppearance="@style/TextAppearanceUnderMenuIcon" />
</LinearLayout>
android:orientation="vertical"
android:layout_gravity="center"
android:gravity="center">
<ImageView
android:id="@+id/iv_medium_select"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|right"
android:focusable="false"
android:visibility="gone"
android:layout_marginRight="6dip"
android:layout_marginBottom="-7dip"
android:src="@drawable/selected" />
</FrameLayout>
<FrameLayout
android:id="@+id/ll_font_large"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/font_normal"
android:layout_marginBottom="5dp" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_gravity="center"
android:gravity="center">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/menu_font_normal"
android:textAppearance="@style/TextAppearanceUnderMenuIcon" />
</LinearLayout>
<ImageView
android:id="@+id/iv_medium_select"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/font_large"
android:layout_marginBottom="5dip" />
android:layout_gravity="bottom|right"
android:focusable="false"
android:visibility="gone"
android:layout_marginRight="6dp"
android:layout_marginBottom="-7dp"
android:src="@drawable/selected" />
</FrameLayout>
<FrameLayout
android:id="@+id/ll_font_large"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1">
<TextView
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/menu_font_large"
android:textAppearance="@style/TextAppearanceUnderMenuIcon" />
</LinearLayout>
android:orientation="vertical"
android:layout_gravity="center"
android:gravity="center">
<ImageView
android:id="@+id/iv_large_select"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|right"
android:focusable="false"
android:visibility="gone"
android:layout_marginRight="6dip"
android:layout_marginBottom="-7dip"
android:src="@drawable/selected" />
</FrameLayout>
<FrameLayout
android:id="@+id/ll_font_super"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/font_large"
android:layout_marginBottom="5dp" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_gravity="center"
android:gravity="center">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/menu_font_large"
android:textAppearance="@style/TextAppearanceUnderMenuIcon" />
</LinearLayout>
<ImageView
android:id="@+id/iv_large_select"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/font_super"
android:layout_marginBottom="5dip" />
android:layout_gravity="bottom|right"
android:focusable="false"
android:visibility="gone"
android:layout_marginRight="6dp"
android:layout_marginBottom="-7dp"
android:src="@drawable/selected" />
</FrameLayout>
<FrameLayout
android:id="@+id/ll_font_super"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1">
<TextView
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/menu_font_super"
android:textAppearance="@style/TextAppearanceUnderMenuIcon" />
</LinearLayout>
android:orientation="vertical"
android:layout_gravity="center"
android:gravity="center">
<ImageView
android:id="@+id/iv_super_select"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|right"
android:focusable="false"
android:visibility="gone"
android:layout_marginRight="6dip"
android:layout_marginBottom="-7dip"
android:src="@drawable/selected" />
</FrameLayout>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/font_super"
android:layout_marginBottom="5dp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/menu_font_super"
android:textAppearance="@style/TextAppearanceUnderMenuIcon" />
</LinearLayout>
<ImageView
android:id="@+id/iv_super_select"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|right"
android:focusable="false"
android:visibility="gone"
android:layout_marginRight="6dp"
android:layout_marginBottom="-7dp"
android:src="@drawable/selected" />
</FrameLayout>
</LinearLayout>
</LinearLayout>
</FrameLayout>
</LinearLayout>

@ -15,51 +15,62 @@
limitations under the License.
-->
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/note_item"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="12dp"
android:background="@null">
<!-- 标题行 -->
<LinearLayout
android:layout_width="fill_parent"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:orientation="horizontal"
android:gravity="center_vertical">
<LinearLayout
android:layout_width="0dip"
<TextView
android:id="@+id/tv_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">
android:textSize="16sp"
android:textColor="@android:color/black"
android:textStyle="bold"
android:maxLines="1"
android:ellipsize="end"
android:singleLine="true" />
<TextView
android:id="@+id/tv_name"
android:layout_width="wrap_content"
android:layout_height="0dip"
android:layout_weight="1"
android:textAppearance="@style/TextAppearancePrimaryItem"
android:visibility="gone" />
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical">
<TextView
android:id="@+id/tv_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:textSize="12sp"
android:textColor="@android:color/darker_gray" />
</LinearLayout>
<TextView
android:id="@+id/tv_title"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1"
android:singleLine="true" />
<!-- 通话名称行(用于通话记录) -->
<TextView
android:id="@+id/tv_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:textSize="14sp"
android:textColor="@android:color/darker_gray"
android:maxLines="1"
android:ellipsize="end"
android:visibility="gone" />
<TextView
android:id="@+id/tv_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/TextAppearanceSecondaryItem" />
</LinearLayout>
</LinearLayout>
<!-- 底部控制行:复选框和提醒图标 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:orientation="horizontal"
android:gravity="center_vertical">
<CheckBox
android:id="@android:id/checkbox"
@ -68,11 +79,27 @@
android:focusable="false"
android:clickable="false"
android:visibility="gone" />
<ImageView
android:id="@+id/iv_alert_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:visibility="gone" />
<!-- 填充空间 -->
<View
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="1" />
<ImageView
android:id="@+id/iv_pinned_icon"
android:layout_width="16dp"
android:layout_height="16dp"
android:src="@android:drawable/ic_menu_upload"
android:tint="@android:color/darker_gray"
android:visibility="gone" />
</LinearLayout>
<ImageView
android:id="@+id/iv_alert_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="top|right"/>
</FrameLayout>
</LinearLayout>

@ -1,59 +1,101 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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.
-->
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@drawable/list_background"
android:fitsSystemWindows="true"
android:paddingTop="24dp">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<TextView
android:id="@+id/tv_title_bar"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="@drawable/title_bar_bg"
android:visibility="gone"
android:gravity="center_vertical"
android:singleLine="true"
android:textColor="#FFEAD1AE"
android:textSize="@dimen/text_font_size_medium" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/notes_list"
android:layout_width="fill_parent"
android:layout_height="0dip"
android:layout_weight="1"
android:cacheColorHint="@null"
android:overScrollMode="never"
android:scrollbars="vertical" />
</LinearLayout>
<Button
android:id="@+id/btn_new_note"
android:background="@drawable/new_note"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:focusable="false"
android:layout_gravity="bottom" />
</FrameLayout>
<!-- 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.
-->
<!-- DrawerLayout支持侧栏滑动 -->
<androidx.drawerlayout.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/list_background">
<!-- 主内容区域 -->
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- AppBarLayout替代传统 ActionBar -->
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/ThemeOverlay.Material3.ActionBar">
<!-- Toolbar现代替代 ActionBar 的标准组件,带汉堡菜单按钮 -->
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:title="@string/app_name"
app:navigationIcon="@android:drawable/ic_menu_sort_by_size"
app:layout_scrollFlags="scroll|enterAlways|snap" />
</com.google.android.material.appbar.AppBarLayout>
<!-- 便签列表:使用 NestedScrollView 包裹 ListView 以支持滚动 -->
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<!-- 面包屑导航:显示当前文件夹路径(在列表上方) -->
<include layout="@layout/breadcrumb_layout" />
<!-- 便签列表 -->
<ListView
android:id="@+id/notes_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="200dp"
android:cacheColorHint="@null"
android:listSelector="@android:color/transparent"
android:divider="@null"
android:fadingEdge="@null" />
</LinearLayout>
</androidx.core.widget.NestedScrollView>
<!-- 悬浮按钮:替代原来的底部按钮 -->
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/btn_new_note"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="16dp"
android:contentDescription="@string/notelist_menu_new"
app:srcCompat="@android:drawable/ic_input_add" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
<!-- 侧栏 -->
<fragment
android:id="@+id/sidebar_fragment"
android:name="net.micode.notes.ui.SidebarFragment"
android:layout_width="280dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:tag="sidebar" />
</androidx.drawerlayout.widget.DrawerLayout>

@ -36,8 +36,4 @@
<item
android:id="@+id/menu_search"
android:title="@string/menu_search"/>
<item
android:id="@+id/menu_switch_layout"
android:title="@string/menu_switch_layout"/>
</menu>

@ -120,7 +120,17 @@
<string name="datetime_dialog_ok">设置</string>
<string name="datetime_dialog_cancel">取消</string>
<plurals name="search_results_title">
<item quantity="other"><xliff:g id="NUMBER">%1$s</xliff:g> 条符合<xliff:g id="SEARCH">%2$s</xliff:g>的搜索结果</item>
<item quantity="other"><xliff:g id="NUMBER">%1$s</xliff:g> 条符合"<xliff:g id="SEARCH">%2$s</xliff:g>"的搜索结果</item>
</plurals>
<!-- Sidebar -->
<string name="root_folder_name">我的便签</string>
<string name="folder_note_count">%d 个便签</string>
<string name="dialog_create_folder_title">创建文件夹</string>
<string name="dialog_create_folder_hint">文件夹名称</string>
<string name="error_folder_name_empty">文件夹名称不能为空</string>
<string name="error_folder_name_too_long">文件夹名称过长最多50个字符</string>
<string name="menu_trash">回收站</string>
<string name="create_folder_success">创建文件夹成功</string>
</resources>

@ -17,4 +17,7 @@
<resources>
<color name="user_query_highlight">#335b5b5b</color>
<color name="primary_color">#1976D2</color>
<color name="on_primary_color">#FFFFFF</color>
<color name="background_color">#FAFAFA</color>
</resources>

@ -48,15 +48,6 @@
<string name="menu_search">Search</string>
<string name="menu_delete">Delete</string>
<string name="menu_move">Move to folder</string>
<string name="menu_switch_layout">Switch Layout</string>
<string name="layout_linear">List Layout</string>
<string name="layout_grid">Grid Layout</string>
<string name="layout_staggered">Staggered Layout</string>
<string name="layout_switch_success">Layout switched to %s</string>
<string name="layout_switch_failed">Failed to switch layout: %s</string>
<string name="layout_settings_title">Layout Settings</string>
<string name="layout_grid_columns">Grid Columns</string>
<string name="layout_item_spacing">Item Spacing</string>
<string name="menu_select_title">%d selected</string>
<string name="menu_select_none">Nothing selected, the operation is invalid</string>
<string name="menu_select_all">Select all</string>
@ -90,6 +81,8 @@
<string name="error_note_not_exist">The note is not exist</string>
<string name="error_note_empty_for_clock">Sorry, can not set clock on empty note</string>
<string name="error_note_empty_for_send_to_desktop">Sorry, can not send and empty note to home</string>
<string name="error_intent_invalid">Invalid intent</string>
<string name="error_intent_unsupported">Unsupported intent action</string>
<string name="success_sdcard_export">Export successful</string>
<string name="failed_sdcard_export">Export fail</string>
<string name="format_exported_file_location">Export text file (%1$s) to SD (%2$s) directory</string>
@ -141,4 +134,24 @@
<item quantity="other"><xliff:g id="number" example="15">%1$s</xliff:g> results for \"<xliff:g id="search" example="???">%2$s</xliff:g>\"</item>
</plurals>
<string name="empty_notes_hint">暂无便签,点击右下角按钮创建</string>
<string name="empty_notes_icon">空便签图标</string>
<string name="menu_edit_note">Edit note</string>
<!-- Sidebar strings -->
<string name="menu_login">Login</string>
<string name="menu_export">Export</string>
<string name="menu_settings">Settings</string>
<string name="menu_trash">Trash</string>
<string name="root_folder_name">My Notes</string>
<string name="sidebar_close">Close sidebar</string>
<string name="sidebar_create_folder">Create folder</string>
<string name="folder_note_count">%d notes</string>
<string name="dialog_create_folder_title">Create folder</string>
<string name="dialog_create_folder_hint">Folder name</string>
<string name="error_folder_name_empty">Folder name cannot be empty</string>
<string name="error_folder_name_too_long">Folder name too long (max 50 characters)</string>
<string name="error_folder_name_exists">Folder already exists</string>
<string name="create_folder_success">Folder created successfully</string>
<string name="menu_pin">Pin</string>
<string name="menu_unpin">Unpin</string>
</resources>

@ -1,9 +1,17 @@
<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> -->
<item name="colorPrimary">@color/primary_color</item>
<item name="colorOnPrimary">@color/on_primary_color</item>
<item name="android:statusBarColor">@color/primary_color</item>
</style>
<style name="Theme.Notesmaster" parent="Base.Theme.Notesmaster" />
<!-- NoteEditActivity使用的主题统一使用Material3风格 -->
<style name="Theme.Notesmaster.Edit" parent="Theme.Material3.Light.NoActionBar">
<item name="colorPrimary">@color/primary_color</item>
<item name="colorOnPrimary">@color/on_primary_color</item>
<item name="android:statusBarColor">@color/primary_color</item>
</style>
</resources>
Loading…
Cancel
Save