diff --git a/.idea/.name b/.idea/.name deleted file mode 100644 index 885be506..00000000 --- a/.idea/.name +++ /dev/null @@ -1 +0,0 @@ -OpenRedmineProject \ No newline at end of file diff --git a/.idea/caches/build_file_checksums.ser b/.idea/caches/build_file_checksums.ser new file mode 100644 index 00000000..bdc0b5ce Binary files /dev/null and b/.idea/caches/build_file_checksums.ser differ diff --git a/.idea/caches/gradle_models.ser b/.idea/caches/gradle_models.ser new file mode 100644 index 00000000..6781e035 Binary files /dev/null and b/.idea/caches/gradle_models.ser differ diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml new file mode 100644 index 00000000..85a749d7 --- /dev/null +++ b/.idea/codeStyles/Project.xml @@ -0,0 +1,153 @@ + + + + + + + + + + + + + + + + + + +
+ + + + xmlns:android + + ^$ + + + +
+
+ + + + xmlns:.* + + ^$ + + + BY_NAME + +
+
+ + + + .*:id + + http://schemas.android.com/apk/res/android + + + +
+
+ + + + .*:name + + http://schemas.android.com/apk/res/android + + + +
+
+ + + + name + + ^$ + + + +
+
+ + + + style + + ^$ + + + +
+
+ + + + .* + + ^$ + + + BY_NAME + +
+
+ + + + .* + + http://schemas.android.com/apk/res/android + + + ANDROID_ATTRIBUTE_ORDER + +
+
+ + + + .* + + .* + + + BY_NAME + +
+
+
+
+
+
\ No newline at end of file diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 00000000..307554b7 --- /dev/null +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml index 03c95a8a..0de2c075 100644 --- a/.idea/modules.xml +++ b/.idea/modules.xml @@ -2,8 +2,8 @@ - - + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml index 94a25f7f..c8397c94 100644 --- a/.idea/vcs.xml +++ b/.idea/vcs.xml @@ -1,6 +1,6 @@ - - - - - + + + + + \ No newline at end of file diff --git a/OpenRedmine/OpenRedmine.iml b/OpenRedmine/OpenRedmine-OpenRedmine.iml similarity index 98% rename from OpenRedmine/OpenRedmine.iml rename to OpenRedmine/OpenRedmine-OpenRedmine.iml index 67d2dd8e..6050bf08 100644 --- a/OpenRedmine/OpenRedmine.iml +++ b/OpenRedmine/OpenRedmine-OpenRedmine.iml @@ -4,8 +4,8 @@ diff --git a/OpenRedmine/src/main/java/jp/redmine/redmineclient/activity/ConnectionActivity.java b/OpenRedmine/src/main/java/jp/redmine/redmineclient/activity/ConnectionActivity.java index f1d73170..39d0de49 100644 --- a/OpenRedmine/src/main/java/jp/redmine/redmineclient/activity/ConnectionActivity.java +++ b/OpenRedmine/src/main/java/jp/redmine/redmineclient/activity/ConnectionActivity.java @@ -17,6 +17,7 @@ import jp.redmine.redmineclient.entity.RedmineFilterSortItem; import jp.redmine.redmineclient.entity.RedmineUser; import jp.redmine.redmineclient.fragment.IssueList; +import jp.redmine.redmineclient.fragment.IssueListAll; import jp.redmine.redmineclient.fragment.ProjectFavoriteList; import jp.redmine.redmineclient.fragment.ProjectList; import jp.redmine.redmineclient.fragment.RecentIssueList; @@ -120,6 +121,20 @@ public Fragment getRawFragment(ConnectionArgument param) { .setIcon(R.drawable.ic_recent) ); + ConnectionArgument argRecent2 = new ConnectionArgument(); + argRecent2.setArgument(); + argRecent2.importArgument(intent); + list.add((new CorePage() { + @Override + public Fragment getRawFragment(ConnectionArgument param) { + return IssueListAll.newInstance(param); + } + }) + .setParam(argRecent2) + .setName("Issues search") + .setIcon(R.drawable.ic_recent) + ); + return list; } diff --git a/OpenRedmine/src/main/java/jp/redmine/redmineclient/adapter/IssueListAdapterAll.java b/OpenRedmine/src/main/java/jp/redmine/redmineclient/adapter/IssueListAdapterAll.java new file mode 100644 index 00000000..c391ec9c --- /dev/null +++ b/OpenRedmine/src/main/java/jp/redmine/redmineclient/adapter/IssueListAdapterAll.java @@ -0,0 +1,173 @@ +package jp.redmine.redmineclient.adapter; + +import java.sql.SQLException; +import java.util.Enumeration; +import java.util.Hashtable; + +import jp.redmine.redmineclient.R; +import jp.redmine.redmineclient.db.cache.DatabaseCacheHelper; +import jp.redmine.redmineclient.db.cache.RedmineFilterModel; +import jp.redmine.redmineclient.entity.RedmineFilter; +import jp.redmine.redmineclient.entity.RedmineFilterSortItem; +import jp.redmine.redmineclient.entity.RedmineIssue; +import jp.redmine.redmineclient.adapter.form.IssueForm; + +import android.content.Context; +import android.text.TextUtils; +import android.util.Log; +import android.view.View; + +import com.j256.ormlite.stmt.QueryBuilder; +import com.j256.ormlite.stmt.Where; + +public class IssueListAdapterAll extends RedmineDaoAdapter { + private static final String TAG = IssueListAdapter.class.getSimpleName(); + private RedmineFilterModel mFilter; + protected Integer connection_id; + protected Long project_id; + protected Integer filter_id; + public IssueListAdapterAll(DatabaseCacheHelper helper, Context context) { + super(helper, context, RedmineIssue.class); + mFilter = new RedmineFilterModel(helper); + } + + public void setupParameter(int connection, long project){ + connection_id = connection; + project_id = project; + } + + public void setupParameter(int filter){ + filter_id = filter; + } + + @Override + public boolean isValidParameter(){ + if(connection_id != null) + return true; + if(filter_id != null) + return true; + return false; + } + + @Override + protected int getItemViewId() { + return R.layout.listitem_issue; + } + + @Override + protected void setupView(View view, RedmineIssue data) { + IssueForm form; + if(view.getTag() != null && view.getTag() instanceof IssueForm){ + form = (IssueForm)view.getTag(); + } else { + form = new IssueForm(view); + } + form.setValue(data); + } + + @Override + protected long getDbItemId(RedmineIssue item) { + if(item == null){ + return -1; + } else { + return item.getId(); + } + } + + public RedmineFilter getParameter() { + RedmineFilter filter = null; + try { + if(filter_id != null) + filter = mFilter.fetchById(filter_id); + else + filter = mFilter.fetchByCurrent(connection_id); + } catch (SQLException e) { + Log.e(TAG, "getParameter", e); + } + if(filter == null) + filter = new RedmineFilter(); + return filter; + } + + @Override + protected QueryBuilder getQueryBuilder() throws SQLException { + RedmineFilter filter = getParameter(); + QueryBuilder builder = dao.queryBuilder(); + Where where = builder.where(); + setupWhere(filter,where); + builder.setWhere(where); + if(TextUtils.isEmpty(filter.getSort())){ + builder.orderBy(RedmineIssue.ISSUE_ID, false); + } else { + for(RedmineFilterSortItem key : filter.getSortList()){ + builder.orderBy(key.getDbKey(),key.isAscending()); + } + } + return builder; + } + @Override + protected QueryBuilder getSearchQueryBuilder(String search) throws SQLException { + RedmineFilter filter = getParameter(); + QueryBuilder builder = dao.queryBuilder(); + Where where = builder.where(); + where + .like(RedmineIssue.SUBJECT, "%" + search + "%") + .or() + .like(RedmineIssue.DESCRIPTION, "%" + search + "%") + ; + if(TextUtils.isDigitsOnly(search)){ + where.or().eq(RedmineIssue.ISSUE_ID, search); + } + where.and(); + + setupWhere(filter, where); + builder.setWhere(where); + if(TextUtils.isEmpty(filter.getSort())){ + builder.orderBy(RedmineIssue.ISSUE_ID, false); + } else { + for(RedmineFilterSortItem key : filter.getSortList()){ + builder.orderBy(key.getDbKey(),key.isAscending()); + } + } + Log.d(TAG, builder.prepareStatementString()); + return builder; + } + + protected void setupWhere(RedmineFilter filter, + Where where) throws SQLException { + Hashtable dic = new Hashtable<>(); + if(filter.getConnectionId() != null) dic.put(RedmineFilter.CONNECTION, filter.getConnectionId()); + //if(filter.getProject() != null) dic.put(RedmineFilter.PROJECT, filter.getProject() ); + if(filter.getTracker() != null) dic.put(RedmineFilter.TRACKER, filter.getTracker() ); + if(filter.getAssigned() != null) dic.put(RedmineFilter.ASSIGNED, filter.getAssigned() ); + if(filter.getAuthor() != null) dic.put(RedmineFilter.AUTHOR, filter.getAuthor() ); + if(filter.getCategory() != null) dic.put(RedmineFilter.CATEGORY, filter.getCategory() ); + if(filter.getStatus() != null) dic.put(RedmineFilter.STATUS, filter.getStatus() ); + if(filter.getVersion() != null) dic.put(RedmineFilter.VERSION, filter.getVersion() ); + if(filter.getPriority() != null) dic.put(RedmineFilter.PRIORITY, filter.getPriority() ); + + boolean isFirst = true; + if(filter.isClosed() != null) { + isFirst = false; + if(filter.isClosed()) + where.isNotNull(RedmineFilter.CLOSED); + else + where.isNull(RedmineFilter.CLOSED); + } + for(Enumeration e = dic.keys() ; e.hasMoreElements() ;){ + String key = e.nextElement(); + if(dic.get(key) == null) + continue; + if(isFirst){ + isFirst = false; + } else { + where.and(); + } + where.eq(key, dic.get(key)); + } + // return no data + if(dic.size() < 1){ + where.eq(RedmineFilter.CONNECTION, -1); + } + } +} diff --git a/OpenRedmine/src/main/java/jp/redmine/redmineclient/db/cache/RedmineFilterModel.java b/OpenRedmine/src/main/java/jp/redmine/redmineclient/db/cache/RedmineFilterModel.java index f02c5575..b9057485 100644 --- a/OpenRedmine/src/main/java/jp/redmine/redmineclient/db/cache/RedmineFilterModel.java +++ b/OpenRedmine/src/main/java/jp/redmine/redmineclient/db/cache/RedmineFilterModel.java @@ -56,6 +56,19 @@ public RedmineFilter fetchByCurrent(int connection,long project) throws SQLExcep item = dao.queryForFirst(builder.prepare()); return item; } + public RedmineFilter fetchByCurrent(int connection) throws SQLException{ + RedmineFilter item; + QueryBuilder builder = dao.queryBuilder(); + Where where = builder.where() + .eq(RedmineFilter.CONNECTION, connection) + .and() + .eq(RedmineFilter.CURRENT, true) + ; + builder.setWhere(where); + Log.d(TAG,builder.prepareStatementString()); + item = dao.queryForFirst(builder.prepare()); + return item; + } public List fetchAllByConnection(int connection) throws SQLException{ List list; QueryBuilder builder = dao.queryBuilder(); @@ -79,6 +92,13 @@ public RedmineFilter generateDefault(int connection,RedmineProject project){ item.setFirst(new Date()); return item; } + public RedmineFilter generateDefault(int connection){ + RedmineFilter item = new RedmineFilter(); + item.setConnectionId(connection); + item.setDefault(true); + item.setFirst(new Date()); + return item; + } public void updateCurrent(RedmineFilter filter) throws SQLException{ RedmineFilter current = fetchByCurrent(filter.getConnectionId(),filter.getProjectId()); if(current != null && current.getId() != filter.getId()){ diff --git a/OpenRedmine/src/main/java/jp/redmine/redmineclient/db/cache/RedminePriorityModel.java b/OpenRedmine/src/main/java/jp/redmine/redmineclient/db/cache/RedminePriorityModel.java index 9f912987..a5304f7d 100644 --- a/OpenRedmine/src/main/java/jp/redmine/redmineclient/db/cache/RedminePriorityModel.java +++ b/OpenRedmine/src/main/java/jp/redmine/redmineclient/db/cache/RedminePriorityModel.java @@ -8,6 +8,7 @@ import java.sql.SQLException; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import jp.redmine.redmineclient.entity.RedmineConnection; @@ -28,7 +29,9 @@ public RedminePriorityModel(DatabaseCacheHelper helper) { } public List fetchAll() throws SQLException{ - return dao.queryForAll(); + List result = dao.queryForAll(); + Collections.sort(result, (o1, o2) -> o1.isDefault() ? 1 : -1); + return result; } public List fetchAll(int connection) throws SQLException{ @@ -37,6 +40,7 @@ public List fetchAll(int connection) throws SQLException{ if(item == null){ item = new ArrayList<>(); } + Collections.sort(item, (o1, o2) -> o1.isDefault() ? 1 : -1); return item; } @@ -126,7 +130,7 @@ public RedminePriority fetchItemByProject(int connection_id, builder .limit(limit) .offset(offset) - .orderBy(RedminePriority.NAME, true) + .orderBy("is_default", false) .where() .eq(RedminePriority.CONNECTION, connection_id) //.and() diff --git a/OpenRedmine/src/main/java/jp/redmine/redmineclient/db/cache/RedmineStatusModel.java b/OpenRedmine/src/main/java/jp/redmine/redmineclient/db/cache/RedmineStatusModel.java index fb934fcf..f87a5914 100644 --- a/OpenRedmine/src/main/java/jp/redmine/redmineclient/db/cache/RedmineStatusModel.java +++ b/OpenRedmine/src/main/java/jp/redmine/redmineclient/db/cache/RedmineStatusModel.java @@ -81,7 +81,7 @@ public RedmineStatus fetchItemByProject(int connection_id, builder .limit(limit) .offset(offset) - .orderBy(RedmineStatus.NAME, true) + .orderBy(RedmineStatus.ID, true) .where() .eq(RedmineStatus.CONNECTION, connection_id) //.and() diff --git a/OpenRedmine/src/main/java/jp/redmine/redmineclient/db/cache/RedmineTrackerModel.java b/OpenRedmine/src/main/java/jp/redmine/redmineclient/db/cache/RedmineTrackerModel.java index 1bafe205..46b65d45 100644 --- a/OpenRedmine/src/main/java/jp/redmine/redmineclient/db/cache/RedmineTrackerModel.java +++ b/OpenRedmine/src/main/java/jp/redmine/redmineclient/db/cache/RedmineTrackerModel.java @@ -123,7 +123,7 @@ public RedmineTracker fetchItemByProject(int connection_id, builder .limit(limit) .offset(offset) - .orderBy(RedmineTracker.NAME, true) + .orderBy(RedmineTracker.ID, true) .where() .eq(RedmineTracker.CONNECTION, connection_id) //.and() diff --git a/OpenRedmine/src/main/java/jp/redmine/redmineclient/fragment/ConnectionEdit.java b/OpenRedmine/src/main/java/jp/redmine/redmineclient/fragment/ConnectionEdit.java index 2193aa75..42ad27f1 100644 --- a/OpenRedmine/src/main/java/jp/redmine/redmineclient/fragment/ConnectionEdit.java +++ b/OpenRedmine/src/main/java/jp/redmine/redmineclient/fragment/ConnectionEdit.java @@ -33,6 +33,7 @@ public class ConnectionEdit extends OrmLiteFragment { private ConnectionModel modelConnection; private ConnectionActionInterface mListener; + private boolean loaded = false; public ConnectionEdit(){ super(); @@ -94,7 +95,9 @@ public void onStart() { ConnectionArgument intent = new ConnectionArgument(); intent.setArgument(getArguments()); idEditing = intent.getConnectionId(); - loadData(); + if (!loaded) { + loadData(); + } } @@ -109,6 +112,7 @@ protected void loadData(){ if(con.getId() != null) { form.setValue(con); + loaded = true; } else { idEditing = -1; } diff --git a/OpenRedmine/src/main/java/jp/redmine/redmineclient/fragment/IssueEdit.java b/OpenRedmine/src/main/java/jp/redmine/redmineclient/fragment/IssueEdit.java index c2344957..b442d7bd 100644 --- a/OpenRedmine/src/main/java/jp/redmine/redmineclient/fragment/IssueEdit.java +++ b/OpenRedmine/src/main/java/jp/redmine/redmineclient/fragment/IssueEdit.java @@ -1,6 +1,7 @@ package jp.redmine.redmineclient.fragment; import android.os.Bundle; +import android.support.v4.view.ViewPager; import android.support.v4.widget.SwipeRefreshLayout; import android.util.Log; import android.view.LayoutInflater; @@ -9,6 +10,7 @@ import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; +import android.widget.TabHost; import android.widget.Toast; import com.j256.ormlite.android.apptools.OrmLiteFragment; @@ -37,6 +39,7 @@ public class IssueEdit extends OrmLiteFragment { private IssueEditForm form; private IssueActionInterface mListener; private SwipeRefreshLayout mSwipeRefreshLayout; + private boolean loaded = false; public IssueEdit(){ super(); @@ -46,7 +49,7 @@ public IssueEdit(){ static public IssueEdit newInstance(IssueArgument intent){ IssueEdit instance = new IssueEdit(); instance.setArguments(intent.getArgument()); - return instance; + return instance; } @Override @@ -75,7 +78,9 @@ public void onActivityCreated(Bundle savedInstanceState) { public void onStart() { super.onStart(); try { - onRefresh(true); + if (!loaded) { + onRefresh(true); + } } catch (SQLException e) { Log.e(TAG,"onStart",e); } @@ -103,6 +108,7 @@ protected void onRefresh(boolean isFetch) throws SQLException{ form.setupParameter(connectionid, projectid); form.setValue(issue); + loaded = true; } @Override @@ -173,6 +179,11 @@ protected void onPostExecute(List result) { if(result.size() == 1) mListener.onIssueRefreshed(connection.getId(), result.get(0).getIssueId()); } + Toast.makeText(getActivity().getApplicationContext(), R.string.remote_saved, Toast.LENGTH_LONG).show(); + if(result.size() == 1) + mListener.onIssueRefreshed(connection.getId(), result.get(0).getIssueId()); + ViewPager viewPager = (ViewPager) getActivity().findViewById(R.id.pager); + viewPager.setCurrentItem(0); } }; if(mSwipeRefreshLayout != null) { diff --git a/OpenRedmine/src/main/java/jp/redmine/redmineclient/fragment/IssueList.java b/OpenRedmine/src/main/java/jp/redmine/redmineclient/fragment/IssueList.java index 11c5b967..e7f3af7c 100644 --- a/OpenRedmine/src/main/java/jp/redmine/redmineclient/fragment/IssueList.java +++ b/OpenRedmine/src/main/java/jp/redmine/redmineclient/fragment/IssueList.java @@ -171,7 +171,7 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, @Override public void onResume() { super.onResume(); - onRefreshList(); + onRefresh(); } @Override diff --git a/OpenRedmine/src/main/java/jp/redmine/redmineclient/fragment/IssueListAll.java b/OpenRedmine/src/main/java/jp/redmine/redmineclient/fragment/IssueListAll.java new file mode 100644 index 00000000..33b55b00 --- /dev/null +++ b/OpenRedmine/src/main/java/jp/redmine/redmineclient/fragment/IssueListAll.java @@ -0,0 +1,369 @@ +package jp.redmine.redmineclient.fragment; + +import android.annotation.TargetApi; +import android.app.Activity; +import android.content.Intent; +import android.os.AsyncTask.Status; +import android.os.Build; +import android.os.Bundle; +import android.support.v4.widget.ListFragmentSwipeRefreshLayout; +import android.support.v4.widget.SwipeRefreshLayout; +import android.support.v7.widget.SearchView; +import android.text.TextUtils; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AbsListView; +import android.widget.AbsListView.OnScrollListener; +import android.widget.AdapterView; +import android.widget.AdapterView.OnItemLongClickListener; +import android.widget.ListView; + +import com.j256.ormlite.android.apptools.OrmLiteListFragment; + +import java.sql.SQLException; + +import jp.redmine.redmineclient.R; +import jp.redmine.redmineclient.activity.FilterViewActivity; +import jp.redmine.redmineclient.activity.WebViewActivity; +import jp.redmine.redmineclient.activity.handler.IssueActionInterface; +import jp.redmine.redmineclient.adapter.IssueListAdapter; +import jp.redmine.redmineclient.adapter.IssueListAdapterAll; +import jp.redmine.redmineclient.db.cache.DatabaseCacheHelper; +import jp.redmine.redmineclient.db.cache.RedmineProjectModel; +import jp.redmine.redmineclient.entity.RedmineConnection; +import jp.redmine.redmineclient.entity.RedmineFilter; +import jp.redmine.redmineclient.entity.RedmineIssue; +import jp.redmine.redmineclient.entity.RedmineProject; +import jp.redmine.redmineclient.entity.TypeConverter; +import jp.redmine.redmineclient.fragment.form.IssueFilterHeaderForm; +import jp.redmine.redmineclient.fragment.helper.ActivityHandler; +import jp.redmine.redmineclient.model.ConnectionModel; +import jp.redmine.redmineclient.param.ConnectionArgument; +import jp.redmine.redmineclient.param.FilterArgument; +import jp.redmine.redmineclient.param.ProjectArgument; +import jp.redmine.redmineclient.param.WebArgument; +import jp.redmine.redmineclient.task.SelectIssueTaskAll; +import jp.redmine.redmineclient.task.SelectProjectEnumerationTask; + +public class IssueListAll extends OrmLiteListFragment implements SwipeRefreshLayout.OnRefreshListener { + private static final String TAG = IssueListAll.class.getSimpleName(); + private static final int ACTIVITY_FILTER = 2001; + private IssueListAdapterAll adapter; + private SelectDataTask task; + private MenuItem menu_refresh; + private MenuItem menu_add; + private View mFooter; + private View mHeader; + private long lastPos = -1; + private boolean isBlockFetch = false; + + private IssueActionInterface mListener; + public IssueListAll(){ + super(); + } + + static public IssueListAll newInstance(ConnectionArgument arg){ + IssueListAll fragment = new IssueListAll(); + fragment.setArguments(arg.getArgument()); + return fragment; + } + + @Override + public void onDestroyView() { + cancelTask(); + setListAdapter(null); + super.onDestroyView(); + } + protected void cancelTask(){ + // cleanup task + if(task != null && task.getStatus() == Status.RUNNING){ + task.cancel(true); + } + } + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + + mListener = ActivityHandler.getHandler(getActivity(), IssueActionInterface.class); + getListView().addFooterView(mFooter); + getListView().addHeaderView(mHeader); + + getListView().setFastScrollEnabled(true); + getListView().setTextFilterEnabled(true); + + adapter = new IssueListAdapterAll(getHelper(), getActivity()); + FilterArgument intent = new FilterArgument(); + intent.setArgument( getArguments() ); + if(intent.hasFilterId()){ + adapter.setupParameter(intent.getFilterId()); + } else { + adapter.setupParameter(intent.getConnectionId(), 10); + } + onRefreshList(); + if(adapter.getCount() < 1){ + this.onRefresh(true); + } + setListAdapter(adapter); + + getListView().setOnItemLongClickListener(new OnItemLongClickListener() { + + @Override + public boolean onItemLongClick(AdapterView parent, View view, int position, long arg3) { + ListView listView = (ListView) parent; + Object listitem = listView.getItemAtPosition(position); + if(listitem == null || ! RedmineIssue.class.isInstance(listitem) ) + { + return false; + } + RedmineIssue item = (RedmineIssue) listitem; + mListener.onIssueEdit(item.getConnectionId(), item.getIssueId()); + return true; + } + }); + + getListView().setOnScrollListener(new OnScrollListener() { + @Override + public void onScroll(AbsListView view, int firstVisibleItem, + int visibleItemCount, int totalItemCount) { + if (totalItemCount == firstVisibleItem + visibleItemCount) { + if(task != null && task.getStatus() == Status.RUNNING) + return; + if(lastPos == totalItemCount) + return; + onRefresh(false); + lastPos = totalItemCount; + } + } + @Override + public void onScrollStateChanged(AbsListView arg0, int arg1) { + + } + }); + isBlockFetch = false; + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setHasOptionsMenu(true); + } + SwipeRefreshLayout mSwipeRefreshLayout; + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + mFooter = inflater.inflate(R.layout.listview_footer,null); + mFooter.setVisibility(View.GONE); + mHeader = inflater.inflate(R.layout.listheader_filter,null); + View view = super.onCreateView(inflater, container, savedInstanceState); + ListFragmentSwipeRefreshLayout.ViewRefreshLayout result + = ListFragmentSwipeRefreshLayout.inject(container, view); + mSwipeRefreshLayout = result.layout; + mSwipeRefreshLayout.setOnRefreshListener(this); + return result.parent; + } + + @Override + public void onResume() { + super.onResume(); + onRefresh(); + } + + @Override + public void onListItemClick(ListView parent, View v, int position, long id) { + super.onListItemClick(parent, v, position, id); + if(v == mHeader){ + if(adapter != null && adapter.getParameter() != null && adapter.getParameter().isCurrent()) + intentFilterAction(); + return; + } + Object listitem = parent.getItemAtPosition(position); + if(listitem == null || ! RedmineIssue.class.isInstance(listitem) ) + { + return; + } + RedmineIssue item = (RedmineIssue) listitem; + mListener.onIssueSelected(item.getConnectionId(), item.getIssueId()); + } + + protected void onRefresh(boolean isFlush){ + if(task != null && task.getStatus() == Status.RUNNING){ + return; + } + onRefreshList(); + if(isBlockFetch) + return; + if(lastPos != getListView().getChildCount()){ + lastPos = -1; //reset + } + + FilterArgument intent = new FilterArgument(); + intent.setArgument(getArguments()); + DatabaseCacheHelper helper = getHelper(); + RedmineConnection connection = ConnectionModel.getItem(getActivity(), intent.getConnectionId()); + if(intent.hasFilterId()) + task = new SelectDataTask(helper,connection,null,intent.getFilterId()); + else + task = new SelectDataTask(helper,connection,1); + + task.execute(0,10,isFlush ? 1 : 0); + /* + if(isFlush && !intent.hasFilterId()){ + RedmineProject project = null; + RedmineProjectModel mProject = new RedmineProjectModel(helper); + try { + project = mProject.fetchById(intent.getProjectId()); + if(menu_add != null) + menu_add.setEnabled(project.getStatus().isUpdateable()); + } catch (SQLException e) { + Log.e(TAG,"SelectDataTask",e); + } + SelectProjectEnumerationTask enumtask = new SelectProjectEnumerationTask(helper,connection,project); + enumtask.execute(); + } + */ + } + protected void onRefreshList(){ + if(adapter == null) + return; + adapter.notifyDataSetChanged(); + IssueFilterHeaderForm form = new IssueFilterHeaderForm(mHeader); + RedmineFilter filter = adapter.getParameter(); + form.setValue(filter); + if (filter != null && !TextUtils.isEmpty(filter.getName())){ + getActivity().setTitle(filter.getName()); + } + + } + + @Override + public void onRefresh() { + onRefresh(true); + } + + private class SelectDataTask extends SelectIssueTaskAll { + public SelectDataTask(DatabaseCacheHelper helper,RedmineConnection connection, long project) { + super(helper,connection,project); + } + public SelectDataTask(DatabaseCacheHelper helper,RedmineConnection connection,Long proj, int filter) { + super(helper,connection,proj,filter); + } + + // can use UI thread here + @Override + protected void onPreExecute() { + mFooter.setVisibility(View.VISIBLE); + if(menu_refresh != null) + menu_refresh.setEnabled(false); + if(mSwipeRefreshLayout != null && !mSwipeRefreshLayout.isRefreshing()) + mSwipeRefreshLayout.setRefreshing(true); + } + + // can use UI thread here + @Override + protected void onPostExecute(Void b) { + mFooter.setVisibility(View.GONE); + onRefreshList(); + if(menu_refresh != null) + menu_refresh.setEnabled(true); + if(mSwipeRefreshLayout != null) + mSwipeRefreshLayout.setRefreshing(false); + } + + @Override + protected void onProgress(int max, int proc) { + onRefreshList(); + super.onProgress(max, proc); + } + } + + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + FilterArgument intent = new FilterArgument(); + intent.setArgument( getArguments() ); + if(!intent.hasFilterId()){ + inflater.inflate( R.menu.issues, menu ); + } + inflater.inflate( R.menu.refresh, menu ); + menu_refresh = menu.findItem(R.id.menu_refresh); + menu_add = menu.findItem(R.id.menu_access_addnew); + if(task != null && task.getStatus() == Status.RUNNING) + menu_refresh.setEnabled(false); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) + setupSearchBar(menu); + inflater.inflate( R.menu.web, menu ); + super.onCreateOptionsMenu(menu, inflater); + } + + @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) + protected void setupSearchBar(Menu menu){ + SearchView search = new SearchView(getActivity()); + search.setIconifiedByDefault(false); + search.setSubmitButtonEnabled(true); + search.setOnQueryTextListener(new SearchView.OnQueryTextListener() { + @Override + public boolean onQueryTextSubmit(String s) { + Integer issue_id = TypeConverter.parseInteger(s); + if (issue_id != null){ + ConnectionArgument intent = new ConnectionArgument(); + intent.setArgument(getArguments()); + mListener.onIssueSelected(intent.getConnectionId(), issue_id); + return true; + } else { + return onQueryTextChange(s); + } + } + + @Override + public boolean onQueryTextChange(String s) { + if (TextUtils.isEmpty(s)) { + isBlockFetch = false; + getListView().clearTextFilter(); + } else { + isBlockFetch = true; + getListView().setFilterText(s); + } + return true; + } + }); + menu.add(android.R.string.search_go) + .setIcon(android.R.drawable.ic_menu_search) + .setActionView(search) + .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM | MenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW) + ; + } + + protected void intentFilterAction(){ + ConnectionArgument intent = new ConnectionArgument(); + intent.setArgument( getArguments() ); + ConnectionArgument send = new ConnectionArgument(); + send.setIntent( getActivity(), FilterViewActivity.class ); + send.setConnectionId(intent.getConnectionId()); + //send.setProjectId(intent.getProjectId()); + startActivityForResult(send.getIntent(), ACTIVITY_FILTER); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) + { + return false; + } + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + switch(requestCode){ + case ACTIVITY_FILTER: + if(resultCode != Activity.RESULT_OK ) + break; + this.onRefresh(false); + break; + default: + break; + } + } + +} diff --git a/OpenRedmine/src/main/java/jp/redmine/redmineclient/fragment/IssueView.java b/OpenRedmine/src/main/java/jp/redmine/redmineclient/fragment/IssueView.java index bbcf1f46..bd79653b 100644 --- a/OpenRedmine/src/main/java/jp/redmine/redmineclient/fragment/IssueView.java +++ b/OpenRedmine/src/main/java/jp/redmine/redmineclient/fragment/IssueView.java @@ -148,7 +148,8 @@ protected void onPostExecute(Void result) { if(isSuccess){ Toast.makeText(getActivity().getApplicationContext(), R.string.remote_saved, Toast.LENGTH_LONG).show(); formComment.clear(); - } + onRefresh(); + } } }; if(mSwipeRefreshLayout != null && !mSwipeRefreshLayout.isRefreshing()) diff --git a/OpenRedmine/src/main/java/jp/redmine/redmineclient/fragment/form/IssueEditForm.java b/OpenRedmine/src/main/java/jp/redmine/redmineclient/fragment/form/IssueEditForm.java index 199dda3f..7a07bad9 100644 --- a/OpenRedmine/src/main/java/jp/redmine/redmineclient/fragment/form/IssueEditForm.java +++ b/OpenRedmine/src/main/java/jp/redmine/redmineclient/fragment/form/IssueEditForm.java @@ -171,10 +171,10 @@ public void setupDatabase(DatabaseCacheHelper helper){ } public void setupParameter(int connection, long project){ - setupParameter(spinnerStatus, adapterStatus, connection, project, true); - setupParameter(spinnerTracker, adapterTracker, connection, project, true); + setupParameter(spinnerStatus, adapterStatus, connection, project, false); + setupParameter(spinnerTracker, adapterTracker, connection, project, false); setupParameter(spinnerCategory, adapterCategory, connection, project, true); - setupParameter(spinnerPriority, adapterPriority, connection, project, true); + setupParameter(spinnerPriority, adapterPriority, connection, project, false); setupParameter(spinnerAssigned, adapterUser, connection, project, true); setupParameter(spinnerVersion, adapterVersion, connection, project, true); diff --git a/OpenRedmine/src/main/java/jp/redmine/redmineclient/task/SelectIssuePost.java b/OpenRedmine/src/main/java/jp/redmine/redmineclient/task/SelectIssuePost.java index 27e438eb..4c3a517c 100644 --- a/OpenRedmine/src/main/java/jp/redmine/redmineclient/task/SelectIssuePost.java +++ b/OpenRedmine/src/main/java/jp/redmine/redmineclient/task/SelectIssuePost.java @@ -62,7 +62,12 @@ public void onData(RedmineConnection info, RedmineIssue data) throws SQLExceptio if (item.getIssueId() == null) { url.setIssueId((Integer) null); - postData(client, url, handler, puthandler); + try { + postData(client, url, handler, puthandler); + + } catch (Exception e) { + + } } else { url.setIssueId(item.getIssueId()); boolean isSuccess = putData(client, url, handler, puthandler); diff --git a/OpenRedmine/src/main/java/jp/redmine/redmineclient/task/SelectIssueTaskAll.java b/OpenRedmine/src/main/java/jp/redmine/redmineclient/task/SelectIssueTaskAll.java new file mode 100644 index 00000000..0233e917 --- /dev/null +++ b/OpenRedmine/src/main/java/jp/redmine/redmineclient/task/SelectIssueTaskAll.java @@ -0,0 +1,156 @@ +package jp.redmine.redmineclient.task; + +import org.xmlpull.v1.XmlPullParserException; + +import java.io.IOException; +import java.io.InputStream; +import java.sql.SQLException; +import java.util.Date; + +import jp.redmine.redmineclient.db.cache.DatabaseCacheHelper; +import jp.redmine.redmineclient.db.cache.RedmineFilterModel; +import jp.redmine.redmineclient.db.cache.RedmineProjectModel; +import jp.redmine.redmineclient.entity.RedmineConnection; +import jp.redmine.redmineclient.entity.RedmineFilter; +import jp.redmine.redmineclient.entity.RedmineProject; +import jp.redmine.redmineclient.parser.IssueModelDataCreationHandler; +import jp.redmine.redmineclient.parser.ParserIssue; +import jp.redmine.redmineclient.url.RemoteUrlIssues; + +public class SelectIssueTaskAll extends SelectDataTask { + + protected DatabaseCacheHelper helper; + protected Long project_id; + protected Integer filter_id; + protected RedmineConnection connection; + public SelectIssueTaskAll(DatabaseCacheHelper helper, RedmineConnection con, long proj){ + this.helper = helper; + this.project_id = proj; + this.connection = con; + } + public SelectIssueTaskAll(DatabaseCacheHelper helper, RedmineConnection con, Long proj, int filter){ + this.helper = helper; + this.filter_id = filter; + this.connection = con; + } + + + public SelectIssueTaskAll() { + } + + + protected RedmineFilter getFilter(RedmineFilterModel mFilter){ + + RedmineFilter filter = null; + try { + if(filter_id == null){ + //RedmineProjectModel mProject = new RedmineProjectModel(helper); + //RedmineProject project = mProject.fetchById(project_id); + filter = mFilter.fetchByCurrent(connection.getId()); + if(filter == null){ + filter = mFilter.generateDefault(connection.getId()); + filter.setCurrent(true); + } + } else { + filter = mFilter.fetchById(filter_id); + } + } catch (SQLException e) { + publishError(e); + } + return filter; + } + protected void updateFilter(RedmineFilterModel mFilter, RedmineFilter filter){ + try { + mFilter.updateOrInsert(filter); + } catch (SQLException e) { + publishError(e); + } + + } + @Override + protected Void doInBackground(Integer... params) { + long limit = params[1]; + boolean isRest = (params.length > 2 && params[2] == 1); + RedmineFilterModel mFilter = new RedmineFilterModel(helper); + RedmineFilter filter = getFilter(mFilter); + if(filter == null) + return null; + + /* + Calendar cal = Calendar.getInstance(); + cal.add(Calendar.DATE, 10); ///@todo + if(filter.getFirst() == null || cal.after(filter.getFirst())) + filter.setFetched(0); + */ + long lastfetched = filter.getFetched(); + long fetched = 0; + + //accelerate fetch issues + if(isRest){ + if(lastfetched <= 0){ + lastfetched = limit; + } + if(lastfetched > (limit*2)) + limit *= 2; + } else { + fetched = lastfetched; + lastfetched += limit; + } + + SelectDataTaskRedmineConnectionHandler client = new SelectDataTaskRedmineConnectionHandler(connection); + final ParserIssue parser = new ParserIssue(); + SelectDataTaskDataHandler taskhandler = new SelectDataTaskDataHandler() { + @Override + public void onContent(InputStream stream) + throws XmlPullParserException, IOException, SQLException { + IssueModelDataCreationHandler handler = new IssueModelDataCreationHandler(helper); + parser.registerDataCreation(handler); + helperSetupParserStream(stream, parser); + parser.parse(connection); + } + }; + RemoteUrlIssues url = new RemoteUrlIssues(); + RemoteUrlIssues.setupFilter(url, filter, filter.isClosed() == null ? true : filter.isClosed()); + try { + boolean isFirst = true; + while(fetched < lastfetched){ + url.filterOffset((int)fetched); + url.filterLimit((int)limit); + fetchData(client, url, taskhandler); + + // update fetch status + fetched += parser.getCount(); + if(parser.getCount() < 1) + break; + + //update offset for next fetch + fetched++; + if(isFirst){ + //sleep for server + Thread.sleep(1000); + isFirst = false; + } + } + fetched--; + filter.setFetched(fetched); + filter.setLast(new Date()); + updateFilter(mFilter,filter); + } catch (InterruptedException e) { + publishError(e); + } + + return null; + } + + @Override + protected void onErrorRequest(int statuscode) { + + } + + @Override + protected void onProgress(int max, int proc) { + + } + + +} diff --git a/build.gradle b/build.gradle index 5579311a..7f7c3a35 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:3.5.0' + classpath 'com.android.tools.build:gradle:3.5.3' } } diff --git a/OpenRedmineProject.iml b/git-OpenRedmine.iml similarity index 75% rename from OpenRedmineProject.iml rename to git-OpenRedmine.iml index 73f8ae3c..f2470eb1 100644 --- a/OpenRedmineProject.iml +++ b/git-OpenRedmine.iml @@ -1,5 +1,5 @@ - +