From adf5cfc4bde05ce4005a83582a0cc01c89bf3ef9 Mon Sep 17 00:00:00 2001 From: SheYu <2893251844@qq.com> Date: Thu, 18 Jan 2024 19:02:44 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9C=80=E7=BB=88=E4=BB=A3=E7=A0=81=E5=90=88?= =?UTF-8?q?=E5=B9=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/AndroidManifest.xml | 22 +- .../notes/gtask/remote/GTaskASyncTask.java | 63 ++--- .../notes/gtask/remote/GTaskClient.java | 220 ++++++------------ .../notes/gtask/remote/GTaskManager.java | 63 ++--- .../notes/gtask/remote/GTaskSyncService.java | 15 ++ .../net/micode/notes/ui/NoteEditActivity.java | 108 +++++++-- src/main/res/layout/note_edit.xml | 9 - src/main/res/values/strings.xml | 1 - 8 files changed, 201 insertions(+), 300 deletions(-) diff --git a/src/main/AndroidManifest.xml b/src/main/AndroidManifest.xml index 3b7012e..972f9a0 100644 --- a/src/main/AndroidManifest.xml +++ b/src/main/AndroidManifest.xml @@ -1,20 +1,4 @@ - - - + android:requestLegacyExternalStorage="true" + android:testOnly="true" > { private static int GTASK_SYNC_NOTIFICATION_ID = 5234235; @@ -69,22 +62,9 @@ public class GTaskASyncTask extends AsyncTask { message }); } - /** - * @method showNotification - * @description: 向用户提示当前同步的状态,是一个用于交互的方法 - * @date: 2023/12/24 20:50 - * @author: WuShuxian - * @param: - * @return: - */ + private void showNotification(int tickerId, String content) { - Notification notification = new Notification(R.drawable.notification, mContext - .getString(tickerId), System.currentTimeMillis()); - notification.defaults = Notification.DEFAULT_LIGHTS; - notification.flags = Notification.FLAG_AUTO_CANCEL; PendingIntent pendingIntent; - //如果同步不成功,那么从系统取得一个用于启动一个NotesPreferenceActivity的PendingIntent对象 - //如果同步成功,那么从系统取得一个用于启动一个NotesListActivity的PendingIntent对象 if (tickerId != R.string.ticker_success) { pendingIntent = PendingIntent.getActivity(mContext, 0, new Intent(mContext, NotesPreferenceActivity.class), 0); @@ -93,18 +73,21 @@ public class GTaskASyncTask extends AsyncTask { pendingIntent = PendingIntent.getActivity(mContext, 0, new Intent(mContext, NotesListActivity.class), 0); } - //notification.setLatestEventInfo(mContext, mContext.getString(R.string.app_name), content, - //pendingIntent); + + + Notification.Builder builder = new Notification.Builder(mContext) + .setAutoCancel(true) + .setContentTitle(mContext.getString(R.string.app_name)) + .setContentText(content) + .setContentIntent(pendingIntent) + .setWhen(System.currentTimeMillis()) + .setOngoing(true); + Notification notification=builder.getNotification(); mNotifiManager.notify(GTASK_SYNC_NOTIFICATION_ID, notification); } - /** - * @method doInBackground - * @description: 此方法在后台线程执行,完成任务的主要工作,通常需要较长的时间 - * @date: 2023/12/24 20:51 - * @author: WuShuxian - * @param: - * @return: - */ + + + @Override protected Integer doInBackground(Void... unused) { publishProgess(mContext.getString(R.string.sync_progress_login, NotesPreferenceActivity @@ -112,14 +95,6 @@ public class GTaskASyncTask extends AsyncTask { return mTaskManager.sync(mContext, this); } - /** - * @method onProgressUpdate - * @description: 可以使用进度条增加用户体验度。 此方法在主线程执行,用于显示任务执行的进度 - * @date: 2023/12/24 20:51 - * @author: WuShuxian - * @param: - * @return: - */ @Override protected void onProgressUpdate(String... progress) { showNotification(R.string.ticker_syncing, progress[0]); @@ -128,14 +103,6 @@ public class GTaskASyncTask extends AsyncTask { } } - /** - * @method onPostExecute - * @description: 相当于Handler 处理UI的方式,在这里面可以使用在doInBackground 得到的结果处理操作UI - * @date: 2023/12/24 20:51 - * @author: WuShuxian - * @param: - * @return: - */ @Override protected void onPostExecute(Integer result) { if (result == GTaskManager.STATE_SUCCESS) { diff --git a/src/main/java/net/micode/notes/gtask/remote/GTaskClient.java b/src/main/java/net/micode/notes/gtask/remote/GTaskClient.java index f8a0547..c67dfdf 100644 --- a/src/main/java/net/micode/notes/gtask/remote/GTaskClient.java +++ b/src/main/java/net/micode/notes/gtask/remote/GTaskClient.java @@ -60,14 +60,7 @@ import java.util.zip.GZIPInputStream; import java.util.zip.Inflater; import java.util.zip.InflaterInputStream; -/** - * @Package: net.micode.notes.gtask.remote - * @ClassName: GTaskClient - * @Description: 实现GTASK的登录操作,进行GTASK任务的创建,创建任务列表,从网络上获取任务和任务列表的内容 - * @Author: WuShuxian - * @CreateDate: 2023/12/24 20:55 - * @Version: 1.0 - */ + public class GTaskClient { private static final String TAG = GTaskClient.class.getSimpleName(); @@ -97,12 +90,6 @@ public class GTaskClient { private JSONArray mUpdateArray; - /** - * @method GTaskClient - * @description: 构造函数 - * @date: 2023/12/24 20:56 - * @author: WuShuxian - */ private GTaskClient() { mHttpClient = null; mGetUrl = GTASK_GET_URL; @@ -121,40 +108,35 @@ public class GTaskClient { } return mInstance; } - /** - * @method login - * @description: 用来实现登录操作,有两种登录方式,使用用户自己的URL登录或者使用谷歌官方的URL登录 - * @date: 2023/12/24 21:15 - * @author: WuShuxian - * @param: activity - * @return: boolean - */ + public boolean login(Activity activity) { - //判断距离最后一次登录操作是否超过5分钟 + // we suppose that the cookie would expire after 5 minutes + // then we need to re-login final long interval = 1000 * 60 * 5; if (mLastLoginTime + interval < System.currentTimeMillis()) { mLoggedin = false; } - // 重新登陆操作 + // need to re-login after account switch if (mLoggedin && !TextUtils.equals(getSyncAccount().name, NotesPreferenceActivity .getSyncAccountName(activity))) { mLoggedin = false; } - //如果没超过时间,则不需要重新登录 + if (mLoggedin) { Log.d(TAG, "already logged in"); return true; } - mLastLoginTime = System.currentTimeMillis();//更新最后登录时间为系统当前的时间 - String authToken = loginGoogleAccount(activity, false);//判断是否登录到谷歌账户 + mLastLoginTime = System.currentTimeMillis(); + String authToken = loginGoogleAccount(activity, false); if (authToken == null) { Log.e(TAG, "login google account failed"); return false; } + // login with custom domain if necessary if (!(mAccount.name.toLowerCase().endsWith("gmail.com") || mAccount.name.toLowerCase() .endsWith("googlemail.com"))) { StringBuilder url = new StringBuilder(GTASK_URL).append("a/"); @@ -168,7 +150,8 @@ public class GTaskClient { mLoggedin = true; } } - //如果用户账户无法登录,则使用谷歌官方的URI进行登录 + + // try to login with google official url if (!mLoggedin) { mGetUrl = GTASK_GET_URL; mPostUrl = GTASK_POST_URL; @@ -180,14 +163,7 @@ public class GTaskClient { mLoggedin = true; return true; } - /** - * @method loginGoogleAccount - * @description: 具体实现登录谷歌账户的方法 - * @date: 2023/12/24 23:07 - * @author: WuShuxian - * @param: activity - * @return: String - */ + private String loginGoogleAccount(Activity activity, boolean invalidateToken) { String authToken; AccountManager accountManager = AccountManager.get(activity); @@ -200,7 +176,6 @@ public class GTaskClient { String accountName = NotesPreferenceActivity.getSyncAccountName(activity); Account account = null; - //遍历获得的accounts信息,寻找已经记录过的账户信息 for (Account a : accounts) { if (a.name.equals(accountName)) { account = a; @@ -214,7 +189,7 @@ public class GTaskClient { return null; } - //获取令牌 + // get the token now AccountManagerFuture accountManagerFuture = accountManager.getAuthToken(account, "goanna_mobile", null, activity, null, null); try { @@ -231,16 +206,11 @@ public class GTaskClient { return authToken; } - /** - * @method tryToLoginGtask - * @description: 尝试登陆Gtask,这只是一个预先判断令牌是否是有效以及是否能登上GTask的方法,而不是具体实现登陆的方法 - * @date: 2023/12/24 21:01 - * @author: WuShuxian - * @param: - * @return: - */ + private boolean tryToLoginGtask(Activity activity, String authToken) { if (!loginGtask(authToken)) { + // maybe the auth token is out of date, now let's invalidate the + // token and try again authToken = loginGoogleAccount(activity, true); if (authToken == null) { Log.e(TAG, "login google account failed"); @@ -254,33 +224,26 @@ public class GTaskClient { } return true; } - /** - * @method loginGtask - * @description: 具体实现登录操作 - * @date: 2023/12/24 21:05 - * @author: WuShuxian - * @param: - * @return: - */ + private boolean loginGtask(String authToken) { int timeoutConnection = 10000; - int timeoutSocket = 15000; //socket是一种通信连接实现数据的交换的端口 - HttpParams httpParameters = new BasicHttpParams(); //实例化一个新的HTTP参数类 - HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutConnection);//设置连接超时时间 - HttpConnectionParams.setSoTimeout(httpParameters, timeoutSocket);//设置设置端口超时时间 + int timeoutSocket = 15000; + HttpParams httpParameters = new BasicHttpParams(); + HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutConnection); + HttpConnectionParams.setSoTimeout(httpParameters, timeoutSocket); mHttpClient = new DefaultHttpClient(httpParameters); BasicCookieStore localBasicCookieStore = new BasicCookieStore(); mHttpClient.setCookieStore(localBasicCookieStore); HttpProtocolParams.setUseExpectContinue(mHttpClient.getParams(), false); - //登录操作 + // login gtask try { - String loginUrl = mGetUrl + "?auth=" + authToken;//设置登录的URL - HttpGet httpGet = new HttpGet(loginUrl);//通过登录的uri实例化网页上资源的查找 + String loginUrl = mGetUrl + "?auth=" + authToken; + HttpGet httpGet = new HttpGet(loginUrl); HttpResponse response = null; response = mHttpClient.execute(httpGet); - //获取CookieStore里存放的cookie,如果存有“GTL”,则cookie有效 + // get the cookie now List cookies = mHttpClient.getCookieStore().getCookies(); boolean hasAuthCookie = false; for (Cookie cookie : cookies) { @@ -292,7 +255,7 @@ public class GTaskClient { Log.w(TAG, "it seems that there is no auth cookie"); } - //获取client的内容 + // get the client version String resString = getResponseContent(response.getEntity()); String jsBegin = "_setup("; String jsEnd = ")}"; @@ -309,6 +272,7 @@ public class GTaskClient { e.printStackTrace(); return false; } catch (Exception e) { + // simply catch all exceptions Log.e(TAG, "httpget gtask_url failed"); return false; } @@ -319,24 +283,14 @@ public class GTaskClient { private int getActionId() { return mActionId++; } - /** - * @method createHttpPost - * @description: 实例化创建一个用于向网络传输数据的对象 - * @date: 2023/12/24 23:13 - * @author: WuShuxian - */ + private HttpPost createHttpPost() { HttpPost httpPost = new HttpPost(mPostUrl); httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded;charset=utf-8"); httpPost.setHeader("AT", "1"); return httpPost; } - /** - * @method getResponseContent - * @description: 通过URL获取响应后返回的数据,也就是网络上的数据和资源 - * @date: 2023/12/24 21:06 - * @author: WuShuxian - */ + private String getResponseContent(HttpEntity entity) throws IOException { String contentEncoding = null; if (entity.getContentEncoding() != null) { @@ -368,20 +322,13 @@ public class GTaskClient { input.close(); } } - /** - * @method postRequest - * @description: 通过Json发送请求 - * @date: 2023/12/24 21:07 - * @author: WuShuxian - * @param: js - * @return: - */ + private JSONObject postRequest(JSONObject js) throws NetworkFailureException { if (!mLoggedin) { Log.e(TAG, "please login first"); throw new ActionFailureException("not logged in"); } - //实例化一个httpPost的对象用来向服务器传输数据,在这里就是发送请求,而请求的内容在js里 + HttpPost httpPost = createHttpPost(); try { LinkedList list = new LinkedList(); @@ -389,8 +336,9 @@ public class GTaskClient { UrlEncodedFormEntity entity = new UrlEncodedFormEntity(list, "UTF-8"); httpPost.setEntity(entity); + // execute the post HttpResponse response = mHttpClient.execute(httpPost); - String jsString = getResponseContent(response.getEntity());//得到返回的数据和资源 + String jsString = getResponseContent(response.getEntity()); return new JSONObject(jsString); } catch (ClientProtocolException e) { @@ -411,25 +359,21 @@ public class GTaskClient { throw new ActionFailureException("error occurs when posting request"); } } - /** - * @method createTask - * @description: 创建单个任务 - * @date: 2023/12/24 21:08 - * @author: WuShuxian - * @param: task - * @return: void - */ + public void createTask(Task task) throws NetworkFailureException { commitUpdate(); try { JSONObject jsPost = new JSONObject(); JSONArray actionList = new JSONArray(); + // action_list actionList.put(task.getCreateAction(getActionId())); jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList); + // client_version jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion); + // post JSONObject jsResponse = postRequest(jsPost); JSONObject jsResult = (JSONObject) jsResponse.getJSONArray( GTaskStringUtils.GTASK_JSON_RESULTS).get(0); @@ -441,29 +385,25 @@ public class GTaskClient { throw new ActionFailureException("create task: handing jsonobject failed"); } } - /** - * @method createTaskList - * @description: 建一个任务列表,与createTask几乎一样,区别就是最后设置的是tasklist的gid - * @date: 2023/12/24 21:09 - * @author: WuShuxian - * @param: tasklist - * @return: void - */ + public void createTaskList(TaskList tasklist) throws NetworkFailureException { commitUpdate(); try { JSONObject jsPost = new JSONObject(); JSONArray actionList = new JSONArray(); + // action_list actionList.put(tasklist.getCreateAction(getActionId())); jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList); + // client version jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion); - JSONObject jsResponse = postRequest(jsPost);//得到任务的返回信息 + // post + JSONObject jsResponse = postRequest(jsPost); JSONObject jsResult = (JSONObject) jsResponse.getJSONArray( GTaskStringUtils.GTASK_JSON_RESULTS).get(0); - tasklist.setGid(jsResult.getString(GTaskStringUtils.GTASK_JSON_NEW_ID));//设置task的new_id + tasklist.setGid(jsResult.getString(GTaskStringUtils.GTASK_JSON_NEW_ID)); } catch (JSONException e) { Log.e(TAG, e.toString()); @@ -477,8 +417,10 @@ public class GTaskClient { try { JSONObject jsPost = new JSONObject(); + // action_list jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, mUpdateArray); + // client_version jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion); postRequest(jsPost); @@ -490,17 +432,11 @@ public class GTaskClient { } } } - /** - * @method addUpdateNode - * @description: 添加更新的事项 - * @date: 2023/12/24 23:19 - * @author: WuShuxian - * @param: node - * @return: void - */ + public void addUpdateNode(Node node) throws NetworkFailureException { if (node != null) { - //设置更新(同步)项目数量上限:10 + // too many update items may result in an error + // set max to 10 items if (mUpdateArray != null && mUpdateArray.length() > 10) { commitUpdate(); } @@ -510,14 +446,7 @@ public class GTaskClient { mUpdateArray.put(node.getUpdateAction(getActionId())); } } - /** - * @method moveTask - * @description: 移动task,比如讲task移动到不同的task列表中去 - * @date: 2023/12/24 23:19 - * @author: WuShuxian - * @param: task、preParent、curParent - * @return: void - */ + public void moveTask(Task task, TaskList preParent, TaskList curParent) throws NetworkFailureException { commitUpdate(); @@ -526,22 +455,26 @@ public class GTaskClient { JSONArray actionList = new JSONArray(); JSONObject action = new JSONObject(); - // 动作序列 + // action_list action.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE, GTaskStringUtils.GTASK_JSON_ACTION_TYPE_MOVE); action.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, getActionId()); action.put(GTaskStringUtils.GTASK_JSON_ID, task.getGid()); if (preParent == curParent && task.getPriorSibling() != null) { - action.put(GTaskStringUtils.GTASK_JSON_PRIOR_SIBLING_ID, task.getPriorSibling());//设置优先级ID,只有当移动是发生在文件中 + // put prioring_sibing_id only if moving within the tasklist and + // it is not the first one + action.put(GTaskStringUtils.GTASK_JSON_PRIOR_SIBLING_ID, task.getPriorSibling()); } action.put(GTaskStringUtils.GTASK_JSON_SOURCE_LIST, preParent.getGid()); action.put(GTaskStringUtils.GTASK_JSON_DEST_PARENT, curParent.getGid()); if (preParent != curParent) { - action.put(GTaskStringUtils.GTASK_JSON_DEST_LIST, curParent.getGid());//仅当在任务列表之间移动时才放入dest_list + // put the dest_list only if moving between tasklists + action.put(GTaskStringUtils.GTASK_JSON_DEST_LIST, curParent.getGid()); } actionList.put(action); - jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList);//将ACTION_LIST加入到jsPost中 + jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList); + // client_version jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion); postRequest(jsPost); @@ -552,27 +485,22 @@ public class GTaskClient { throw new ActionFailureException("move task: handing jsonobject failed"); } } - /** - * @method deleteNode - * @description: 删除操作节点 - * @date: 2023/12/24 23:22 - * @author: WuShuxian - * @param: node - * @return: void - */ + public void deleteNode(Node node) throws NetworkFailureException { commitUpdate(); try { JSONObject jsPost = new JSONObject(); JSONArray actionList = new JSONArray(); + // action_list node.setDeleted(true); - actionList.put(node.getUpdateAction(getActionId()));//获取删除操作的ID,加入actionLiast + actionList.put(node.getUpdateAction(getActionId())); jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList); + // client_version jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion); - postRequest(jsPost);//使用postRequest发送删除后的结果 + postRequest(jsPost); mUpdateArray = null; } catch (JSONException e) { Log.e(TAG, e.toString()); @@ -580,14 +508,7 @@ public class GTaskClient { throw new ActionFailureException("delete node: handing jsonobject failed"); } } - /** - * @method getTaskLists - * @description: 获取任务列表 - * @date: 2023/12/24 23:24 - * @author: WuShuxian - * @param: void - * @return: - */ + public JSONArray getTaskLists() throws NetworkFailureException { if (!mLoggedin) { Log.e(TAG, "please login first"); @@ -599,8 +520,8 @@ public class GTaskClient { HttpResponse response = null; response = mHttpClient.execute(httpGet); - // 获取任务列表,把筛选出的字符串放入jsString - String resString = getResponseContent(response.getEntity());//从网上获取数据 + // get the task list + String resString = getResponseContent(response.getEntity()); String jsBegin = "_setup("; String jsEnd = ")}"; int begin = resString.indexOf(jsBegin); @@ -625,14 +546,7 @@ public class GTaskClient { throw new ActionFailureException("get task lists: handing jasonobject failed"); } } - /** - * @method getTaskList - * @description: 通过传入的TASKList的gid,从网络上获取相应属于这个任务列表的任务 - * @date: 2023/12/24 23:28 - * @author: WuShuxian - * @param: listGid - * @return: - */ + public JSONArray getTaskList(String listGid) throws NetworkFailureException { commitUpdate(); try { @@ -640,6 +554,7 @@ public class GTaskClient { JSONArray actionList = new JSONArray(); JSONObject action = new JSONObject(); + // action_list action.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE, GTaskStringUtils.GTASK_JSON_ACTION_TYPE_GETALL); action.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, getActionId()); @@ -648,6 +563,7 @@ public class GTaskClient { actionList.put(action); jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList); + // client_version jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion); JSONObject jsResponse = postRequest(jsPost); diff --git a/src/main/java/net/micode/notes/gtask/remote/GTaskManager.java b/src/main/java/net/micode/notes/gtask/remote/GTaskManager.java index e7771a2..d2b4082 100644 --- a/src/main/java/net/micode/notes/gtask/remote/GTaskManager.java +++ b/src/main/java/net/micode/notes/gtask/remote/GTaskManager.java @@ -47,14 +47,7 @@ import java.util.HashSet; import java.util.Iterator; import java.util.Map; -/** - * @Package: net.micode.notes.gtask.remote - * @ClassName: GTaskManager - * @Description: 同步管理操作 - * @Author: WuShuxian - * @CreateDate: 2023/12/24 21:13 - * @Version: 1.0 - */ + public class GTaskManager { private static final String TAG = GTaskManager.class.getSimpleName(); @@ -93,17 +86,10 @@ public class GTaskManager { private HashMap mGidToNid; private HashMap mNidToGid; - /** - * @method GTaskManager - * @description: 构造函数,初始化实例对象 - * @date: 2023/12/24 23:30 - * @author: WuShuxian - * @param: void - * @return: void - */ + private GTaskManager() { - mSyncing = false;//正在同步,flase代表未执行 - mCancelled = false;//全局标识,flase代表可以执行 + mSyncing = false; + mCancelled = false; mGTaskListHashMap = new HashMap(); mGTaskHashMap = new HashMap(); mMetaHashMap = new HashMap(); @@ -112,14 +98,7 @@ public class GTaskManager { mGidToNid = new HashMap(); mNidToGid = new HashMap(); } - /** - * @method getInstance - * @description: 包含关键字synchronized,语言级同步,指明该函数可能运行在多线程的环境下 - * @date: 2023/12/24 23:31 - * @author: WuShuxian - * @param: void - * @return: GTaskManager - */ + public static synchronized GTaskManager getInstance() { if (mInstance == null) { mInstance = new GTaskManager(); @@ -128,17 +107,10 @@ public class GTaskManager { } public synchronized void setActivityContext(Activity activity) { + // used for getting authtoken mActivity = activity; } - /** - * @method sync - * @description: 用于同步的核心函数,实现了本地同步操作和远端同步操作 - * @date: 2023/12/24 23:32 - * @author: WuShuxian - * @param: context:获取上下文 - * asyncTask:用于同步的异步操作类 - * @return: int - */ + public int sync(Context context, GTaskASyncTask asyncTask) { if (mSyncing) { Log.d(TAG, "Sync is in progress"); @@ -155,9 +127,8 @@ public class GTaskManager { mGidToNid.clear(); mNidToGid.clear(); - //进行同步操作,并作异常处理:网络异常、操作异常 try { - GTaskClient client = GTaskClient.getInstance();//创建一个实例:client + GTaskClient client = GTaskClient.getInstance(); client.resetUpdateArray(); // login google task @@ -168,19 +139,18 @@ public class GTaskManager { } // get the task list from google - //从google获取task list asyncTask.publishProgess(mContext.getString(R.string.sync_progress_init_list)); initGTaskList(); - //进行同步操作 + // do content sync work asyncTask.publishProgess(mContext.getString(R.string.sync_progress_syncing)); syncContent(); } catch (NetworkFailureException e) { Log.e(TAG, e.toString()); - return STATE_NETWORK_ERROR;//网络异常 + return STATE_NETWORK_ERROR; } catch (ActionFailureException e) { Log.e(TAG, e.toString()); - return STATE_INTERNAL_ERROR;//操作异常 + return STATE_INTERNAL_ERROR; } catch (Exception e) { Log.e(TAG, e.toString()); e.printStackTrace(); @@ -197,14 +167,7 @@ public class GTaskManager { return mCancelled ? STATE_SYNC_CANCELLED : STATE_SUCCESS; } - /** - * @method initGTaskList - * @description: 初始化GtaskList,获取Google上的JSONtasklist转为本地TaskList - * @date: 2023/12/24 23:39 - * @author: WuShuxian - * @param: - * @return: - */ + private void initGTaskList() throws NetworkFailureException { if (mCancelled) return; @@ -212,7 +175,7 @@ public class GTaskManager { try { JSONArray jsTaskLists = client.getTaskLists(); - //初始化元列表 + // init meta list first mMetaList = null; for (int i = 0; i < jsTaskLists.length(); i++) { JSONObject object = jsTaskLists.getJSONObject(i); diff --git a/src/main/java/net/micode/notes/gtask/remote/GTaskSyncService.java b/src/main/java/net/micode/notes/gtask/remote/GTaskSyncService.java index cca36f7..174ec76 100644 --- a/src/main/java/net/micode/notes/gtask/remote/GTaskSyncService.java +++ b/src/main/java/net/micode/notes/gtask/remote/GTaskSyncService.java @@ -23,6 +23,14 @@ import android.content.Intent; import android.os.Bundle; import android.os.IBinder; +/** + * @Package: net.micode.notes.gtask.remote + * @ClassName: GTaskSyncService + * @Description: + * @Author: WuShuxian + * @CreateDate: 2024/1/15 21:36 + * @Version: 1.0 + */ public class GTaskSyncService extends Service { public final static String ACTION_STRING_NAME = "sync_action_type"; @@ -118,10 +126,17 @@ public class GTaskSyncService extends Service { context.startService(intent); } + /** + * @method isSyncing + * @description: 查询是否正在同步 + * @date: 2024/1/15 21:38 + * @author: WuShuxian + */ public static boolean isSyncing() { return mSyncTask != null; } + public static String getProgressString() { return mSyncProgress; } diff --git a/src/main/java/net/micode/notes/ui/NoteEditActivity.java b/src/main/java/net/micode/notes/ui/NoteEditActivity.java index b740b4a..917c80f 100644 --- a/src/main/java/net/micode/notes/ui/NoteEditActivity.java +++ b/src/main/java/net/micode/notes/ui/NoteEditActivity.java @@ -14,6 +14,8 @@ import android.content.SharedPreferences; import android.graphics.Paint; import android.os.Bundle; import android.preference.PreferenceManager; +import android.speech.tts.TextToSpeech; +import android.speech.tts.TextToSpeech.OnInitListener; import android.text.Spannable; import android.text.SpannableString; import android.text.TextUtils; @@ -71,6 +73,9 @@ import java.util.regex.Pattern; */ public class NoteEditActivity extends Activity implements OnClickListener, NoteSettingChangedListener, OnTextViewChangeListener { + /** + * 类属性的定义 + */ private class HeadViewHolder { public TextView tvModified; @@ -82,6 +87,7 @@ public class NoteEditActivity extends Activity implements OnClickListener, public TextView textNum; } + private static final Map sBgSelectorBtnsMap = new HashMap(); static { sBgSelectorBtnsMap.put(R.id.iv_bg_yellow, ResourceParser.YELLOW); @@ -123,13 +129,21 @@ public class NoteEditActivity extends Activity implements OnClickListener, "android.permission.WRITE_EXTERNAL_STORAGE" };//权限名称 private static final String TAG = "NoteEditActivity"; + private HeadViewHolder mNoteHeaderHolder; + private View mHeadViewPanel; + private View mNoteBgColorSelector; + private View mFontSizeSelector; + private EditText mNoteEditor; + private View mNoteEditorPanel; - public WorkingNote mWorkingNote; + + private WorkingNote mWorkingNote; + private SharedPreferences mSharedPrefs; private int mFontSizeId; @@ -215,6 +229,8 @@ public class NoteEditActivity extends Activity implements OnClickListener, protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); this.setContentView(R.layout.note_edit); + checkStoragePermissions(this);//动态申请权限 + if (savedInstanceState == null && !initActivityState(getIntent())) { finish(); return; @@ -237,6 +253,7 @@ public class NoteEditActivity extends Activity implements OnClickListener, } }); convertToImage();//将路径显示为图片 + count(); } /** @@ -257,7 +274,6 @@ public class NoteEditActivity extends Activity implements OnClickListener, } } - private boolean initActivityState(Intent intent) { /** * If the user specified the {@link Intent#ACTION_VIEW} but not provided with id, @@ -298,6 +314,7 @@ public class NoteEditActivity extends Activity implements OnClickListener, WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE); } else if(TextUtils.equals(Intent.ACTION_INSERT_OR_EDIT, intent.getAction())) { + // New note long folderId = intent.getLongExtra(Notes.INTENT_EXTRA_FOLDER_ID, 0); int widgetId = intent.getIntExtra(Notes.INTENT_EXTRA_WIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID); @@ -305,6 +322,8 @@ public class NoteEditActivity extends Activity implements OnClickListener, Notes.TYPE_WIDGET_INVALIDE); int bgResId = intent.getIntExtra(Notes.INTENT_EXTRA_BACKGROUND_ID, ResourceParser.getDefaultBgId(this)); + + // Parse call-record note String phoneNumber = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER); long callDate = intent.getLongExtra(Notes.INTENT_EXTRA_CALL_DATE, 0); if (callDate != 0 && phoneNumber != null) { @@ -398,8 +417,7 @@ public class NoteEditActivity extends Activity implements OnClickListener, long time = System.currentTimeMillis(); if (time > mWorkingNote.getAlertDate()) { mNoteHeaderHolder.tvAlertDate.setText(R.string.note_alert_expired); - } - else { + } else { mNoteHeaderHolder.tvAlertDate.setText(DateUtils.getRelativeTimeSpanString( mWorkingNote.getAlertDate(), time, DateUtils.MINUTE_IN_MILLIS)); } @@ -411,12 +429,12 @@ public class NoteEditActivity extends Activity implements OnClickListener, }; } - @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); initActivityState(intent); } + @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); @@ -431,6 +449,7 @@ public class NoteEditActivity extends Activity implements OnClickListener, outState.putLong(Intent.EXTRA_UID, mWorkingNote.getNoteId()); Log.d(TAG, "Save working note id: " + mWorkingNote.getNoteId() + " onSaveInstanceState"); } + @Override public boolean dispatchTouchEvent(MotionEvent ev) { if (mNoteBgColorSelector.getVisibility() == View.VISIBLE @@ -455,10 +474,9 @@ public class NoteEditActivity extends Activity implements OnClickListener, if (ev.getX() < x || ev.getX() > (x + view.getWidth()) || ev.getY() < y - || ev.getY() > (y + view.getHeight())) - { - return false; - } + || ev.getY() > (y + view.getHeight())) { + return false; + } return true; } @@ -495,6 +513,24 @@ public class NoteEditActivity extends Activity implements OnClickListener, mFontSizeId = ResourceParser.BG_DEFAULT_FONT_SIZE; } mEditTextList = (LinearLayout) findViewById(R.id.note_edit_list); + + //朗读 + mTTS = new TextToSpeech(this,new TextToSpeech.OnInitListener(){ + @Override + public void onInit(int status){ + // 判断是否转化成功 + if (status == TextToSpeech.SUCCESS){ + //默认设定语言为中文 + int result = mTTS.setLanguage(Locale.CHINESE); + if (result == TextToSpeech.LANG_MISSING_DATA || result == TextToSpeech.LANG_NOT_SUPPORTED){ + Toast.makeText(NoteEditActivity.this, "Language not available.", Toast.LENGTH_SHORT).show(); + }else{ + //不支持中文就将语言设置为英文 + mTTS.setLanguage(Locale.US); + } + } + } + }); } @Override @@ -530,7 +566,6 @@ public class NoteEditActivity extends Activity implements OnClickListener, setResult(RESULT_OK, intent); } - public void onClick(View v) { int id = v.getId(); if (id == R.id.btn_set_bg_color) { @@ -596,6 +631,7 @@ public class NoteEditActivity extends Activity implements OnClickListener, mNoteEditorPanel.setBackgroundResource(mWorkingNote.getBgColorResId()); mHeadViewPanel.setBackgroundResource(mWorkingNote.getTitleBgResId()); } + @Override public boolean onPrepareOptionsMenu(Menu menu) { if (isFinishing()) { @@ -620,6 +656,7 @@ public class NoteEditActivity extends Activity implements OnClickListener, } return true; } + @Override /** * @method onOptionsItemSelected @@ -662,6 +699,9 @@ public class NoteEditActivity extends Activity implements OnClickListener, setReminder(); } else if (itemId == R.id.menu_delete_remind) { mWorkingNote.setAlertDate(0, false); + } else if (itemId == R.id.menu_voice){ + Log.d("voiceOut","in"); + textToSpeach(); } return true; } @@ -683,7 +723,6 @@ public class NoteEditActivity extends Activity implements OnClickListener, d.show(); } - /** * Share note to apps that support {@link Intent#ACTION_SEND} action * and {@text/plain} type @@ -940,16 +979,20 @@ public class NoteEditActivity extends Activity implements OnClickListener, public void onCheckListModeChanged(int oldMode, int newMode) { if (newMode == TextNote.MODE_CHECK_LIST) { switchToListMode(mNoteEditor.getText().toString()); + //检查模式切换到列表模式 } else { if (!getWorkingText()) { mWorkingNote.setWorkingText(mWorkingNote.getContent().replace(TAG_UNCHECKED + " ", "")); } + //若是获取到文本就改变其检查标记 mNoteEditor.setText(getHighlightQueryResult(mWorkingNote.getContent(), mUserQuery)); mEditTextList.setVisibility(View.GONE); mNoteEditor.setVisibility(View.VISIBLE); + //修改文本编辑器的内容和可见性 } } + /** * @method getWorkingText * @description 获取正在编辑的文本内容 @@ -958,26 +1001,23 @@ public class NoteEditActivity extends Activity implements OnClickListener, * @return 是否存在已打钩的选项 */ private boolean getWorkingText() { - boolean hasChecked = false;//初始化check标记 + boolean hasChecked = false; + //初始化check标记 if (mWorkingNote.getCheckListMode() == TextNote.MODE_CHECK_LIST) { - /** - * 若模式为CHECK_LIST - * 先创建可变字符串 - * 遍历所有子编辑框的视图 - */ + // 若模式为CHECK_LIST StringBuilder sb = new StringBuilder(); + //创建可变字符串 for (int i = 0; i < mEditTextList.getChildCount(); i++) { View view = mEditTextList.getChildAt(i); + //遍历所有子编辑框的视图 NoteEditText edit = (NoteEditText) view.findViewById(R.id.et_edit_text); if (!TextUtils.isEmpty(edit.getText())) { - /** - * 若文本不为空 - * 该选项框已打钩 - * 扩展字符串为已打钩并把标记置true - */ + //若文本不为空 if (((CheckBox) view.findViewById(R.id.cb_edit_item)).isChecked()) { + //该选项框已打钩 sb.append(TAG_CHECKED).append(" ").append(edit.getText()).append("\n"); hasChecked = true; + //扩展字符串为已打钩并把标记置true } else { //扩展字符串添加未打钩 sb.append(TAG_UNCHECKED).append(" ").append(edit.getText()).append("\n"); @@ -985,8 +1025,14 @@ public class NoteEditActivity extends Activity implements OnClickListener, } } mWorkingNote.setWorkingText(sb.toString());//利用编辑好的字符串设置运行便签的内容 + //利用编辑好的字符串设置运行便签的内容 } else {// 若不是该模式直接用编辑器中的内容设置运行中标签的内容 mWorkingNote.setWorkingText(mNoteEditor.getText().toString()); + //若是获取到文本就改变其检查标记 + mNoteEditor.setText(getHighlightQueryResult(mWorkingNote.getContent(), mUserQuery)); + mEditTextList.setVisibility(View.GONE); + mNoteEditor.setVisibility(View.VISIBLE); + //修改文本编辑器的内容和可见性 } return hasChecked; } @@ -1000,6 +1046,11 @@ public class NoteEditActivity extends Activity implements OnClickListener, private boolean saveNote() { getWorkingText(); boolean saved = mWorkingNote.saveNote(); + //如果便签内容为空,则删除 + if (TextUtils.isEmpty(mWorkingNote.getContent())) { + deleteCurrentNote();//删除当前便签 + saved = false; // 标记为未保存 + } //运行 getWorkingText()之后保存 if (saved) { /** @@ -1055,6 +1106,7 @@ public class NoteEditActivity extends Activity implements OnClickListener, showToast(R.string.error_note_empty_for_send_to_desktop); } } + /** * @method makeShortcutIconTitle * @description 生成快捷方式图标标题 @@ -1069,9 +1121,11 @@ public class NoteEditActivity extends Activity implements OnClickListener, return content.length() > SHORTCUT_ICON_TITLE_MAX_LEN ? content.substring(0, SHORTCUT_ICON_TITLE_MAX_LEN) : content; } + private void showToast(int resId) { showToast(resId, Toast.LENGTH_SHORT); } + private void showToast(int resId, int duration) { Toast.makeText(this, resId, duration).show(); } @@ -1292,4 +1346,14 @@ public class NoteEditActivity extends Activity implements OnClickListener, e.printStackTrace(); } } + + /** + * @method textToSpeach + * @description: 朗读功能 + * @date: 2024/1/16 20:21 + * @author: WuShuxian + */ + private void textToSpeach(){ + mTTS.speak(mNoteEditor.getText().toString(),TextToSpeech.QUEUE_FLUSH,null); + } } diff --git a/src/main/res/layout/note_edit.xml b/src/main/res/layout/note_edit.xml index defd4eb..59415d7 100644 --- a/src/main/res/layout/note_edit.xml +++ b/src/main/res/layout/note_edit.xml @@ -405,13 +405,4 @@ android:src="@drawable/selected" /> - - diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index dccf596..469b04c 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -39,7 +39,6 @@ notes_%s.txt (%d) - Add picture New Folder Export text Sync