Explorar o código

1.修改Android Apex Mobile Result,完成用户交互。

Pen Li %!s(int64=7) %!d(string=hai) anos
pai
achega
36f1f27b95

+ 1 - 1
Apex Mobile/app/src/main/java/com/usai/apex/actionSheet/ActionSheet.java

@@ -65,7 +65,7 @@ public class ActionSheet extends Dialog implements View.OnClickListener {
             buttonListenerMap.put(button,clickListener);
         }
 
-        button.setTitleColorForState(RAButton.RAButtonState.RAButtonStateHighlight,Color.RED);
+        button.setTitleColorForState(RAButton.RAButtonState.RAButtonStateHighlight,Color.GRAY);
         button.setBackgroundDrawableForState(RAButton.RAButtonState.RAButtonStateNormal,mCtx.getResources().getDrawable(R.drawable.actionsheet_round_corner_normal_bg));
 
         LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,dp2px(mCtx,50));

+ 400 - 10
Apex Mobile/app/src/main/java/com/usai/apex/apexResult/ApexResultActivity.java

@@ -1,20 +1,46 @@
 package com.usai.apex.apexResult;
 
 import android.app.Activity;
+import android.app.ProgressDialog;
 import android.content.Context;
+import android.content.DialogInterface;
 import android.content.Intent;
+import android.database.sqlite.SQLiteDatabase;
+import android.graphics.Color;
 import android.support.v4.view.MenuItemCompat;
+import android.support.v4.widget.SwipeRefreshLayout;
+import android.support.v7.app.AlertDialog;
 import android.support.v7.app.AppCompatActivity;
 import android.os.Bundle;
+import android.text.TextUtils;
+import android.view.Gravity;
 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.AdapterView;
+import android.widget.EditText;
 import android.widget.ListView;
+import android.widget.ProgressBar;
+import android.widget.TextView;
 
+import com.usai.apex.ApexTrackingApplication;
+import com.usai.apex.CustomizeFieldsActivity;
 import com.usai.apex.R;
+import com.usai.apex.Result.AMResultActivity;
 import com.usai.apex.actionSheet.ActionSheet;
-import com.usai.util.RAUtil;
+import com.usai.apex.mainframe.NewDetailActivity;
+import com.usai.apex.pdf.PDFPreviewActivity;
+import com.usai.util.Network;
+import com.usai.util.commonUtil;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.Iterator;
+
 
 public class ApexResultActivity extends AppCompatActivity implements ApexResultPresenter.ApexResultProtocol {
 
@@ -37,10 +63,26 @@ public class ApexResultActivity extends AppCompatActivity implements ApexResultP
 
     // endregion
 
+    // region Request Code
+
+    private static class RequestCode {
+
+        static final int Field_Setting = 1010;
+    }
+
+    // endregion
+
     // region Property
 
     private Context mCtx = this;
+
     private ListView mListView;
+    private SwipeRefreshLayout mRefreshLayout;
+    private ProgressBar mProgressBar;
+    private TextView mListFooterView;
+
+    private ScrollListener mScrollListener;
+
     private ApexResultPresenter mPresenter;
     private ApexResultAdapter mAdapter;
     private Bundle mParams;
@@ -64,7 +106,6 @@ public class ApexResultActivity extends AppCompatActivity implements ApexResultP
             mParams = new Bundle();
         }
 
-        setupActionBar();
         setup();
 
         if (savedInstanceState != null) {
@@ -79,8 +120,10 @@ public class ApexResultActivity extends AppCompatActivity implements ApexResultP
 
         if (item.getItemId() == android.R.id.home) {
             finish();
+            return  true;
         } else if (item.getItemId() == R.id.apex_result_menu) {
             menuItemClick();
+            return true;
         }
 
         return super.onOptionsItemSelected(item);
@@ -88,7 +131,7 @@ public class ApexResultActivity extends AppCompatActivity implements ApexResultP
 
     @Override
     public boolean onCreateOptionsMenu(Menu menu) {
-        new MenuInflater(mCtx).inflate(R.menu.apex_result_menu, menu);
+        getMenuInflater().inflate(R.menu.apex_result_menu, menu);
         return true;
     }
 
@@ -100,18 +143,73 @@ public class ApexResultActivity extends AppCompatActivity implements ApexResultP
         mPresenter.onSaveInstanceState(outState);
     }
 
+    @Override
+    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+        super.onActivityResult(requestCode, resultCode, data);
+
+        if (requestCode == RequestCode.Field_Setting) {
+            refresh();
+        }
+    }
+
     // endregion
 
     // region Setting
 
     private void setup() {
 
-        mListView = findViewById(R.id.apex_result_list_view);
         mPresenter = new ApexResultPresenter(this, mParams);
         mAdapter = new ApexResultAdapter(mCtx, mPresenter);
+
+        setupActionBar();
+        setupRefreshLayout();
+        setupListView();
+
+        mProgressBar = findViewById(R.id.apex_result_progress_bar);
+    }
+
+    private void setupListView() {
+
+        mListView = findViewById(R.id.apex_result_list_view);
         mListView.setAdapter(mAdapter);
+
+        setupListFooterView();
+        AbsListView.LayoutParams footerLayoutParams = new AbsListView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.WRAP_CONTENT);
+        mListFooterView.setLayoutParams(footerLayoutParams);
+        mListView.addFooterView(mListFooterView);
+
+        mScrollListener = new ScrollListener();
+        mListView.setOnScrollListener(mScrollListener);
+
+        mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
+            @Override
+            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+                clickItemCell(view, position);
+            }
+        });
     }
 
+    private void setupListFooterView() {
+        mListFooterView = new TextView(mCtx);
+        mListFooterView.setBackgroundColor(Color.WHITE);
+        mListFooterView.setGravity(Gravity.CENTER);
+        mListFooterView.setText("loading more...");
+        mListFooterView.setTextSize(commonUtil.sp2px(mCtx,8));
+        mListFooterView.setVisibility(View.INVISIBLE);
+    }
+
+    private void setupRefreshLayout() {
+
+        mRefreshLayout = findViewById(R.id.apex_result_refresh_layout);
+        mRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
+            @Override
+            public void onRefresh() {
+                refresh();
+            }
+        });
+    }
+
+
     private void setupActionBar() {
 
         android.support.v7.app.ActionBar actionBar = getSupportActionBar();
@@ -123,37 +221,92 @@ public class ApexResultActivity extends AppCompatActivity implements ApexResultP
 
     // endregion
 
+    // region Action
+
+    private void refresh() {
+        mPresenter.refreshData();
+    }
+
+    private void loadMore() {
+        mPresenter.loadMoreData();
+    }
+
+    private void clickItemCell(View cell, int position) {
+
+        handleRowAction(position);
+    }
+
+    // endregion
+
+    // region ProgressBar
+
+    public void showProgressBar() {
+        mProgressBar.setVisibility(View.VISIBLE);
+    }
+
+    public void dismissProgressBar() {
+        mProgressBar.setVisibility(View.GONE);
+    }
+
+    // endregion
+
+    // region Alert
+
+    private void showAlertMessage(String msg) {
+        new AlertDialog.Builder(mCtx)
+                .setTitle("Warning")
+                .setMessage(msg)
+                .setPositiveButton("OK",null)
+                .show();
+    }
+
+    // endregion
+
     // region Presenter Delegate
     @Override
     public void onStartLoading() {
-
+        isLoading = true;
+        showProgressBar();
     }
 
     @Override
     public void onStopLoading() {
+        if (mRefreshLayout.isRefreshing()) {
+            mRefreshLayout.setRefreshing(false);
+        }
+        mListFooterView.setVisibility(View.INVISIBLE);
+        dismissProgressBar();
 
+        isLoading = false;
     }
 
     @Override
     public void onSuccess(String title) {
-
         setTitle(title);
         mAdapter.notifyDataSetChanged();
     }
 
     @Override
     public void onFailed(String errMsg) {
-
+        if (errMsg == null) {
+            errMsg = "Sorry, something is wrong.";
+        }
+        showAlertMessage(errMsg);
     }
 
     @Override
     public void onNoMoreData() {
-
+        showAlertMessage("No More Data");
     }
 
     @Override
-    public void onDownloadFile(String path) {
+    public void onDownloadFile(String path, Bundle params) {
+
+        String email = params.getString("email");
+        String email_subject = params.getString("email_subject");
+        String email_content = params.getString("email_content");
 
+        previewPDF(path, email, email_subject, email_content);
     }
     // endregion
 
@@ -190,10 +343,247 @@ public class ApexResultActivity extends AppCompatActivity implements ApexResultP
 
     private void saveSearchParameters() {
 
+        final View edit = new EditText(mCtx);
+        new android.app.AlertDialog.Builder(mCtx)
+                .setIconAttribute(android.R.attr.alertDialogIcon)
+                .setTitle(R.string.str_createname)
+                .setView(edit)
+                .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+                            public void onClick(DialogInterface dialog, int whichButton) {
+
+                                String name = ((EditText) edit).getText().toString();
+                                if(TextUtils.isEmpty(name))
+                                {
+                                    new android.app.AlertDialog.Builder(mCtx)
+                                            .setTitle("Warning")
+                                            .setMessage("Name can not be empty.")
+                                            .setPositiveButton("OK", new DialogInterface.OnClickListener() {
+                                                @Override
+                                                public void onClick(DialogInterface dialog, int which) {
+
+                                                }
+                                            })
+                                            .show();
+                                    return;
+                                }
+
+                                mPresenter.saveSearchParametersWithName(name);
+
+                            }
+                        })
+                .setNegativeButton(android.R.string.cancel, null)
+                .create()
+                .show();
+
     }
 
     private void showFieldsSetting() {
 
+        Intent intent = new Intent();
+        intent.setClass(this, CustomizeFieldsActivity.class);
+        intent.putExtra("user", ApexTrackingApplication.get_user());
+        intent.putExtra("function_name", mParams.getString("module_name"));
+        intent.putExtra("behavior", Network.BEHAVIOR_RESULT);
+        startActivityForResult(intent,RequestCode.Field_Setting);
+    }
+
+    // endregion
+
+    // region Scroll Listener
+
+    private boolean isLoading = false;
+    private class ScrollListener implements AbsListView.OnScrollListener {
+
+        private int last_index, total_index;
+
+        @Override
+        public void onScrollStateChanged(AbsListView view, int scrollState) {
+            if (last_index == total_index && (scrollState == SCROLL_STATE_IDLE)) {
+                if (!isLoading) {
+
+                    mListFooterView.setVisibility(View.VISIBLE);
+                    loadMore();
+                }
+            }
+        }
+
+        @Override
+        public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
+            last_index = firstVisibleItem + visibleItemCount;
+            total_index = totalItemCount;
+        }
+    }
+
+    // endregion
+
+    // region Row Action
+
+    private Bundle paramsForIndex(int position, JSONObject action) {
+
+        JSONArray parameters = mPresenter.rowActionParametersForIndex(position);
+        Bundle params = new Bundle();
+        JSONObject actionParams = action.optJSONObject("params");
+        if (actionParams != null) {
+
+            Iterator<String> keys = actionParams.keys();
+            while (keys.hasNext()) {
+                String key = keys.next();
+                try {
+
+                    int idx = actionParams.getInt(key);
+                    String value = parameters.getString(idx);
+                    params.putString(key, value);
+
+                } catch (Exception e) {
+                    e.printStackTrace();
+                }
+            }
+
+        }
+        return params;
+    }
+
+    private void handleRowAction(int position) {
+
+        JSONArray rowActions = mPresenter.getRowActions();
+        if (rowActions != null) {
+
+            if (rowActions.length() == 1) {
+
+                JSONObject action = rowActions.optJSONObject(0);
+                if (action != null) {
+
+                    Bundle params = paramsForIndex(position, action);
+                    String module = action.optString("module");
+                    if (module != null) {
+                        if (module.equals("quick_look")) {
+
+                            showQuickLookForActionWithParams(action, params);
+
+                        } else if (module.equals("detail")) {
+
+                            showDetailForActionWithParams(action, params);
+                        }
+                    }
+                }
+
+            } else {
+
+                ActionSheet actionSheet = new ActionSheet(mCtx);
+
+                for (int i = 0; i < rowActions.length(); i++) {
+
+                    try {
+
+                        final JSONObject json = rowActions.getJSONObject(i);
+                        final Bundle params = paramsForIndex(position, json);
+
+                        String title = json.getString("title");
+                        final String module = json.getString("module");
+
+                        actionSheet.addAction(title, ActionSheet.ActionType.ActionTypeDefault, new View.OnClickListener() {
+                            @Override
+                            public void onClick(View v) {
+
+                                if (module.equals("quick_look")) {
+
+                                    showQuickLookForActionWithParams(json, params);
+
+                                } else if (module.equals("detail")) {
+
+                                    showDetailForActionWithParams(json, params);
+                                }
+
+                            }
+                        });
+
+                    } catch (JSONException e) {
+                        e.printStackTrace();
+                    }
+
+                } // for
+
+                actionSheet.addAction("Cancel", ActionSheet.ActionType.ACtionTypeCancel, new View.OnClickListener() {
+                    @Override
+                    public void onClick(View v) {
+
+                    }
+                });
+
+                actionSheet.show();
+
+            }
+        }
+    }
+
+    private void showQuickLookForActionWithParams(JSONObject action, Bundle params) {
+
+        try {
+
+            String url = action.getString("url");
+            mPresenter.downloadFile(url, params);
+
+        } catch (JSONException e) {
+            e.printStackTrace();
+        }
+    }
+
+    private void showDetailForActionWithParams(JSONObject action, Bundle params) {
+
+        String module_name = mPresenter.getParams().getString("module_name");
+        String detail_id = params.getString("id");
+        JSONArray actions = mPresenter.getActions();
+        if (actions == null) {
+            actions = new JSONArray();
+        }
+
+        Intent intent = new Intent(mCtx, NewDetailActivity.class);
+        intent.putExtra("function_name", module_name);
+        intent.putExtra("actions_count", actions.length());
+        intent.putExtra("_id",detail_id);
+
+        for (int i = 0; i < actions.length(); i++) {
+            try {
+                String name = actions.getString(i);
+                intent.putExtra("action" + i, name);
+            } catch (JSONException e) {
+                e.printStackTrace();
+            }
+        }
+
+        startActivity(intent);
+    }
+
+    // endregion
+
+    // region PDF
+
+    private void previewPDF(String file,String email,String subject,String content) {
+
+        Intent myIntent = new Intent(mCtx, PDFPreviewActivity.class);
+        myIntent.putExtra("file",file);
+        myIntent.putExtra("iscache",true);
+
+        try {
+            JSONObject json = new JSONObject();
+
+            if (email != null) {
+                json.put("email",email);
+            }
+            if (subject != null) {
+                json.put("subject",subject);
+            }
+            if (content != null) {
+                json.put("content",content);
+            }
+            myIntent.putExtra("email",json.toString());
+
+        } catch (JSONException e) {
+            e.printStackTrace();
+        }
+
+
+        startActivity(myIntent);
     }
 
     // endregion

+ 3 - 0
Apex Mobile/app/src/main/java/com/usai/apex/apexResult/ApexResultAdapter.java

@@ -115,12 +115,15 @@ public class ApexResultAdapter extends BaseAdapter {
                 ApexResultShipCell cell = dequeueShipCell(context, convertView);
                 cell.prepareReuse();
                 cell.setTitle(shipModel.title).setDetail(shipModel.detail).setIcon(shipModel.icon).setPort(shipModel.port).setTime(shipModel.date).setDescription(shipModel.desc);
+                cell.setTransportStage(shipModel.transport_stage);
+
                 ArrayList<ApexResultShipModel.ApexResultAddition> additions = shipModel.getAddition();
                 if (additions != null && additions.size() > 0) {
                     for (ApexResultShipModel.ApexResultAddition addition : additions) {
                         cell.addAddition(addition.name, addition.value);
                     }
                 }
+
                 return cell;
 
             } else if (model.type == ApexResultBaseModel.ApexResultType.APEX_RESULT_TYPE_DOCUMENT.ordinal()) {

+ 232 - 11
Apex Mobile/app/src/main/java/com/usai/apex/apexResult/ApexResultPresenter.java

@@ -1,16 +1,21 @@
 package com.usai.apex.apexResult;
 
 import android.os.Bundle;
+import android.text.TextUtils;
 
+import com.usai.apex.ApexTrackingApplication;
 import com.usai.apex.apexResult.model.ApexResultBaseModel;
 import com.usai.apex.apexResult.model.ApexResultDocumentModel;
 import com.usai.apex.apexResult.model.ApexResultShipModel;
 import com.usai.apex.operationQueue.OperationQueue;
 import com.usai.util.Network;
 
+
 import org.json.JSONArray;
+import org.json.JSONException;
 import org.json.JSONObject;
 
+import java.io.File;
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 
@@ -24,7 +29,7 @@ public class ApexResultPresenter implements ApexResultAdapter.ApexResultAdapterD
         void onSuccess(String title);
         void onFailed(String errMsg);
         void onNoMoreData();
-        void onDownloadFile(String path);
+        void onDownloadFile(String path, Bundle params);
 
     }
     // endregion
@@ -65,15 +70,100 @@ public class ApexResultPresenter implements ApexResultAdapter.ApexResultAdapterD
 
     // region Save Instance
 
+    private static final String Data_Array_Key = "Data_Array_Key";
+    private static final String Offset_Key = "Offset_Key";
+    private static final String Row_Actions_key = "Row_Actions_Key";
+    private static final String Actions_Key = "Actions_Key";
+
     public void onSaveInstanceState(Bundle outState) {
         if (outState != null) {
 
+            outState.putInt(Offset_Key, offset);
+
+            String dataStr = prepareSaveData();
+            if (dataStr != null) {
+                outState.putString(Data_Array_Key, dataStr);
+            }
+
+            if (rowActions != null) {
+                outState.putString(Row_Actions_key, rowActions.toString());
+            }
+
+            if (actions != null) {
+                outState.putString(Actions_Key, actions.toString());
+            }
         }
     }
 
     public void onRestoreInstanceState(Bundle savedInstanceState) {
         if (savedInstanceState != null) {
 
+            offset = savedInstanceState.getInt(Offset_Key);
+
+            String dataStr = savedInstanceState.getString(Data_Array_Key);
+            prepareRestoreData(dataStr);
+
+            try {
+                String js = savedInstanceState.getString(Row_Actions_key);
+                if (js != null) {
+                    rowActions = new JSONArray(js);
+                }
+            } catch (JSONException e) {
+                e.printStackTrace();
+            }
+
+            try {
+                String js = savedInstanceState.getString(Actions_Key);
+                if (js != null) {
+                    actions = new JSONArray(js);
+                }
+            } catch (JSONException e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    private String prepareSaveData() {
+
+        if (mDataArray != null) {
+
+            JSONArray jsonArray = new JSONArray();
+
+            for (ApexResultBaseModel model : mDataArray) {
+                JSONObject item = model.toJson();
+                jsonArray.put(item);
+            }
+
+            return jsonArray.toString();
+        }
+
+        return null;
+    }
+
+    private void prepareRestoreData(String jsonStr) {
+
+        if (jsonStr != null) {
+
+            try {
+
+                JSONArray jsonArray = new JSONArray(jsonStr);
+
+                ArrayList<ApexResultBaseModel> models = new ArrayList<>();
+                for (int i = 0; i < jsonArray.length(); i++) {
+                    JSONObject item = jsonArray.optJSONObject(i);
+                    if (item != null) {
+                        ApexResultBaseModel model = makeModel(item);
+                        if (model != null) {
+                            models.add(model);
+                        }
+                    }
+                }
+                mDataArray = models;
+
+            } catch (JSONException e) {
+                e.printStackTrace();
+            }
+
         }
     }
 
@@ -102,6 +192,26 @@ public class ApexResultPresenter implements ApexResultAdapter.ApexResultAdapterD
         return mDataArray.get(index);
     }
 
+    public JSONArray rowActionParametersForIndex(int position) {
+        ApexResultBaseModel model = modelAtIndex(position);
+        if (model != null) {
+            return model.rowActionParameters;
+        }
+        return null;
+    }
+
+    public JSONArray getRowActions() {
+        return rowActions;
+    }
+
+    public JSONArray getActions() {
+        return actions;
+    }
+
+    public Bundle getParams() {
+        return mParams;
+    }
+
     // endregion
 
     // region DataSource
@@ -118,6 +228,28 @@ public class ApexResultPresenter implements ApexResultAdapter.ApexResultAdapterD
 
     // endregion
 
+    // region Private
+
+    private ApexResultBaseModel makeModel(JSONObject item) {
+        if (item != null) {
+            int type = item.optInt("type", -1);
+            if (type == ApexResultBaseModel.ApexResultType.APEX_RESULT_TYPE_SHIP.ordinal()) {
+
+                ApexResultShipModel model = new ApexResultShipModel();
+                model.setValuesForKeysWithJSON(item);
+                return model;
+            } else if (type == ApexResultBaseModel.ApexResultType.APEX_RESULT_TYPE_DOCUMENT.ordinal()) {
+
+                ApexResultDocumentModel model = new ApexResultDocumentModel();
+                model.setValuesForKeysWithJSON(item);
+                return model;
+            }
+        }
+        return null;
+    }
+
+    // endregion
+
     // region Data
 
     private void loadData(final ApexResultFetchDataType option) {
@@ -167,16 +299,8 @@ public class ApexResultPresenter implements ApexResultAdapter.ApexResultAdapterD
                             JSONObject item = items.optJSONObject(i);
                             if (item != null) {
 
-                                int type = item.optInt("type", -1);
-                                if (type == ApexResultBaseModel.ApexResultType.APEX_RESULT_TYPE_SHIP.ordinal()) {
-
-                                    ApexResultShipModel model = new ApexResultShipModel();
-                                    model.setValuesForKeysWithJSON(item);
-                                    models.add(model);
-                                } else if (type == ApexResultBaseModel.ApexResultType.APEX_RESULT_TYPE_DOCUMENT.ordinal()) {
-
-                                    ApexResultDocumentModel model = new ApexResultDocumentModel();
-                                    model.setValuesForKeysWithJSON(item);
+                                ApexResultBaseModel model = makeModel(item);
+                                if (model != null) {
                                     models.add(model);
                                 }
                             }
@@ -226,4 +350,101 @@ public class ApexResultPresenter implements ApexResultAdapter.ApexResultAdapterD
     }
 
     // endregion
+
+    // region Save Search Parameter
+
+    public void saveSearchParametersWithName(final String name) {
+
+        if (getDelegate() != null) {
+            getDelegate().onStartLoading();
+        }
+
+        final String paramStr = mParams.toString();
+        final String module_name = mParams.getString("module_name");
+
+        OperationQueue.sharedQueue().addOperationTask(new OperationQueue.OperationBackgroundCallBack() {
+            @Override
+            public Object operationDoInBackground() {
+                return Network.saveSearchParametersForModuleWithName(paramStr, module_name, name);
+            }
+        }, new OperationQueue.OperationCompletionCallBack() {
+            @Override
+            public void operationCompletion(Object object) {
+
+                if (getDelegate() != null) {
+
+                    getDelegate().onStopLoading();
+
+                    JSONObject json = (JSONObject)object;
+
+                    int result = Network.RESULT_FALSE;
+                    String msg = "Sorry, something is wrong.";
+                    if (json != null) {
+
+                        result = json.optInt("result", Network.RESULT_FALSE);
+                        if (result != Network.RESULT_TRUE) {
+                            String err_msg = json.optString("err_msg");
+                            if (!TextUtils.isEmpty(err_msg)) {
+                                msg = err_msg;
+                            }
+                        }
+                    } // json
+
+                    if (result != Network.RESULT_TRUE) {
+                        getDelegate().onFailed(msg);
+                    }
+
+                } // != null
+
+
+
+            }
+        }, null);
+    }
+
+    // endregion
+
+    // region Download
+
+    public void downloadFile(final String url, final Bundle params) {
+
+        if (getDelegate() != null) {
+            getDelegate().onStartLoading();
+        }
+
+        OperationQueue.sharedQueue().addOperationTask(new OperationQueue.OperationBackgroundCallBack() {
+            @Override
+            public Object operationDoInBackground() {
+
+                String cacheDir = ApexTrackingApplication.getInstance().getExternalCacheDir().getAbsolutePath();
+
+                final File downloadFile = Network.downloadFile(params, url, cacheDir);
+
+                return downloadFile;
+            }
+        }, new OperationQueue.OperationCompletionCallBack() {
+            @Override
+            public void operationCompletion(Object object) {
+
+                if (getDelegate() != null) {
+
+                    getDelegate().onStopLoading();
+
+                    File file = (File)object;
+                    if (file == null) {
+
+                        getDelegate().onFailed("Sorry, something is wrong.");
+
+                    } else {
+                        getDelegate().onDownloadFile(file.getAbsolutePath(), params);
+                    }
+
+                }
+
+            }
+        }, null);
+
+    }
+
+    // endregion
 }

+ 34 - 0
Apex Mobile/app/src/main/java/com/usai/apex/apexResult/model/ApexResultBaseModel.java

@@ -1,11 +1,45 @@
 package com.usai.apex.apexResult.model;
 
+import android.os.Parcel;
+import android.os.Parcelable;
+
 import com.usai.apex.base.BaseObject;
 
 import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
 
 public class ApexResultBaseModel extends BaseObject {
 
+    protected ApexResultBaseModel(Parcel in) {
+        type = in.readInt();
+        String jsonStr = in.readString();
+        try {
+            rowActionParameters = new JSONArray(jsonStr);
+        } catch (JSONException e) {
+            e.printStackTrace();
+        }
+    }
+
+    public ApexResultBaseModel() {
+
+    }
+
+    public JSONObject toJson() {
+        JSONObject json = new JSONObject();
+        try {
+            json.put("type", type);
+            if (rowActionParameters != null) {
+                json.put("rowActionParameters", rowActionParameters);
+            }
+
+        } catch (JSONException e) {
+            e.printStackTrace();
+        }
+
+        return json;
+    }
+
     public static enum ApexResultType {
         APEX_RESULT_TYPE_SHIP,
         APEX_RESULT_TYPE_DOCUMENT

+ 28 - 0
Apex Mobile/app/src/main/java/com/usai/apex/apexResult/model/ApexResultDocumentModel.java

@@ -1,8 +1,36 @@
 package com.usai.apex.apexResult.model;
 
+import org.json.JSONException;
+import org.json.JSONObject;
+
 public class ApexResultDocumentModel extends ApexResultBaseModel {
 
     public String fileName;
     public String fileType;
     public String fileDesc;
+
+    public ApexResultDocumentModel() {
+
+    }
+
+    @Override
+    public JSONObject toJson() {
+        JSONObject json = super.toJson();
+
+        try {
+            if (fileName != null) {
+                json.put("fileName", fileName);
+            }
+            if (fileType != null) {
+                json.put("fileType", fileType);
+            }
+            if (fileDesc != null) {
+                json.put("fileDesc", fileDesc);
+            }
+        } catch (JSONException e) {
+            e.printStackTrace();
+        }
+
+        return json;
+    }
 }

+ 58 - 3
Apex Mobile/app/src/main/java/com/usai/apex/apexResult/model/ApexResultShipModel.java

@@ -1,32 +1,47 @@
 package com.usai.apex.apexResult.model;
 
+import android.os.Parcel;
+import android.os.Parcelable;
+
 import com.usai.apex.base.BaseObject;
 
 import org.json.JSONArray;
+import org.json.JSONException;
 import org.json.JSONObject;
 
 import java.util.ArrayList;
 
 public class ApexResultShipModel extends ApexResultBaseModel {
 
-    public class ApexResultAddition extends BaseObject {
+    // region Addition
+    public static class ApexResultAddition extends BaseObject{
         public String name;
         public String value;
+
+        private ApexResultAddition() {
+
+        }
     }
+    // endregion
 
+    // region Model
     public String title;
     public String icon;
     public String desc;
     public String detail;
     public String date;
     public String port;
-    public String transport_stage;
+    public int transport_stage;
 
     public Object addition; // 使用Object对象,便于baseObject赋值
     private ArrayList<ApexResultAddition> additions;
 
-    public void setAddition(Object obj) {
+    public ApexResultShipModel() {
+
+    }
 
+    public void setAddition(Object obj) {
+        this.addition = obj;
         if (obj != null && obj instanceof JSONArray) {
 
             JSONArray addition = (JSONArray) obj;
@@ -58,4 +73,44 @@ public class ApexResultShipModel extends ApexResultBaseModel {
     public ArrayList<ApexResultAddition> getAddition() {
         return additions;
     }
+    // endregion
+
+
+    @Override
+    public JSONObject toJson() {
+        JSONObject json = super.toJson();
+
+        try {
+
+            if (title != null) {
+                json.put("title", title);
+            }
+            if (icon != null) {
+                json.put("icon", icon);
+            }
+            if (desc != null) {
+                json.put("desc", desc);
+            }
+            if (detail != null) {
+                json.put("detail", detail);
+            }
+            if (date != null) {
+                json.put("date", date);
+            }
+            if (port != null) {
+                json.put("port", port);
+            }
+
+            json.put("transport_stage", transport_stage);
+
+            if (addition != null) {
+                json.put("addition", addition);
+            }
+
+        } catch (JSONException e) {
+            e.printStackTrace();
+        }
+
+        return json;
+    }
 }

+ 19 - 0
Apex Mobile/app/src/main/java/com/usai/util/Network.java

@@ -127,6 +127,7 @@ public class Network
 	// 2019.1.5
 	public static String		URL_UPLOAD_SQL					= "https://ra.apexshipping.com/main_new.php";
 	public static String		URL_FETCH_RESULT				= "https://ra.apexshipping.com/main_new.php";
+	public static String		URL_SAVE_RESULT					= "https://ra.apexshipping.com/main_new.php";
 
 
 
@@ -1942,9 +1943,27 @@ public class Network
 			url = "http://192.168.1.150:8080/MyWeb/SearchDoc";
 		}
 
+		try {
+			Thread.sleep(2000);
+		} catch (InterruptedException e) {
+			e.printStackTrace();
+		}
+
 		// URL_FETCH_RESULT
 		String jstr = getJson(url, params);
 
 		return handleResponse(jstr);
 	}
+
+	public static JSONObject saveSearchParametersForModuleWithName(String paramStr, String module, String name) {
+
+		Bundle params = new Bundle();
+		params.putString("params", paramStr);
+		params.putString("module_name", module);
+		params.putString("name", name);
+
+		String jstr = getJson(URL_SAVE_RESULT,params);
+
+		return handleResponse(jstr);
+	}
 }

+ 20 - 4
Apex Mobile/app/src/main/res/layout/activity_apex_result.xml

@@ -7,12 +7,28 @@
     android:layout_height="match_parent"
     tools:context=".apexResult.ApexResultActivity">
 
-    <ListView
-        android:id="@+id/apex_result_list_view"
+    <android.support.v4.widget.SwipeRefreshLayout
+        android:id="@+id/apex_result_refresh_layout"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
-        android:divider="@null"
-        android:listSelector="#00000000"
+        >
+
+        <ListView
+            android:id="@+id/apex_result_list_view"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:divider="@null"
+            android:listSelector="#00000000"
+            />
+
+    </android.support.v4.widget.SwipeRefreshLayout>
+
+    <ProgressBar
+        android:id="@+id/apex_result_progress_bar"
+        android:layout_width="100dp"
+        android:layout_height="100dp"
+        android:layout_centerInParent="true"
+        android:visibility="gone"
         />
 
 </RelativeLayout>

+ 14 - 6
Apex Mobile/app/src/main/res/layout/apex_result_ship_cell.xml

@@ -13,7 +13,7 @@
 
     </RelativeLayout>
 
-    <RelativeLayout
+    <LinearLayout
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:layout_marginLeft="5dp"
@@ -21,15 +21,18 @@
         android:layout_marginBottom="5dp"
         android:background="@drawable/apex_result_cell_bg"
         android:clipChildren="true"
+        android:orientation="horizontal"
         >
 
 
         <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
                       xmlns:app="http://schemas.android.com/apk/res-auto"
-                      android:layout_width="match_parent"
+                      android:layout_width="0dp"
                       android:layout_height="wrap_content"
+                      android:layout_weight="1"
                       android:orientation="vertical"
-                      android:layout_marginRight="10dp"
+                      android:layout_marginRight="5dp"
+                      android:layout_marginEnd="5dp"
             >
 
             <android.support.constraint.ConstraintLayout
@@ -51,8 +54,10 @@
                     android:id="@+id/tv_title"
                     android:layout_width="0dp"
                     android:layout_height="wrap_content"
-                    android:layout_marginEnd="13dp"
+                    android:layout_marginLeft="13dp"
                     android:layout_marginStart="13dp"
+                    android:layout_marginRight="3dp"
+                    android:layout_marginEnd="3dp"
                     android:layout_marginTop="8dp"
                     android:ellipsize="end"
                     android:singleLine="true"
@@ -68,6 +73,7 @@
                     android:layout_width="0dp"
                     android:layout_height="wrap_content"
                     android:layout_marginRight="8dp"
+                    android:layout_marginEnd="8dp"
                     android:layout_marginTop="2dp"
                     android:text="TextView"
                     android:textColor="@color/icon_red"
@@ -93,6 +99,7 @@
                     android:layout_width="0dp"
                     android:layout_height="16dp"
                     android:layout_marginLeft="7dp"
+                    android:layout_marginStart="7dp"
                     android:ellipsize="end"
                     android:singleLine="true"
                     android:text="TextView"
@@ -108,6 +115,7 @@
                     android:layout_height="0dp"
                     android:layout_marginBottom="2dp"
                     android:layout_marginLeft="7dp"
+                    android:layout_marginStart="7dp"
                     android:layout_marginTop="2dp"
                     android:ellipsize="end"
                     android:lines="2"
@@ -127,6 +135,7 @@
                 android:layout_height="wrap_content"
                 android:orientation="vertical"
                 android:layout_marginLeft="13dp"
+                android:layout_marginStart="13dp"
                 >
 
             </LinearLayout>
@@ -138,10 +147,9 @@
             android:layout_width="5dp"
             android:layout_height="match_parent"
             android:background="@drawable/list_corner_transport_stage_bg_0"
-            android:layout_alignParentRight="true"
             />
 
-    </RelativeLayout>
+    </LinearLayout>