Pārlūkot izejas kodu

[필터][New] 필터/세부 필터 적용 로직 수정
- 세부 필터 로드 시 기초 itemNo 를 제대로 적용하지 못했던 점 수정
- 세부 필터 로드 시 waiter 추가 -> 필터 기본 로딩으로 변경 필요

hyodong.min 6 gadi atpakaļ
vecāks
revīzija
79e3181722

+ 72 - 0
app/src/main/java/kr/co/zumo/app/lifeplus/model/module/FilterDetailParser.java

@@ -0,0 +1,72 @@
+/*
+ * COPYRIGHT (c) 2018 All rights reserved by HANWHA LIFE.
+ */
+package kr.co.zumo.app.lifeplus.model.module;
+
+import java.util.List;
+
+import kr.co.zumo.app.lifeplus.bean.api.FilterBean;
+import kr.co.zumo.app.lifeplus.bean.api.FilterTagBean;
+import kr.co.zumo.app.lifeplus.util.StringUtil;
+
+/**
+ * FilterDetailParser
+ * <pre>
+ * </pre>
+ *
+ * @author 민효동
+ * @version 1.0
+ * @history 민효동   [2019. 2. 27.]   [최초 작성]
+ * @since 2019. 2. 27.
+ */
+public class FilterDetailParser {
+
+  public void parse(FilterBean filterBean,  List<FilterTagBean> tagBeans) {
+
+    // '전체' 태그는 tag no 를 'all' 로 변환
+    for (FilterTagBean tagBean : tagBeans) {
+      if (FilterTagBean.INDEX_TOTAL.equals(tagBean.getTagNo()) || FilterTagBean.TAG_NAME_TOTAL.equals(tagBean.getTagName())) {
+        tagBean.setTagNo(FilterTagBean.TAG_NO_TOTAL);
+        break;
+      }
+    }
+
+    // 이전 선택한 항목 재 선택
+    if (null != filterBean.getTagBeans()) {
+      for (FilterTagBean before : filterBean.getTagBeans()) {
+        String tagNo = before.getTagNo();
+        if (StringUtil.isFull(tagNo)) {
+          for (FilterTagBean tag : tagBeans) {
+            if (tagNo.equals(tag.getTagNo())) {
+              tag.setSelected(before.isSelected());
+              if (before.canCommit() == false) {
+                // 커밋한 상태로 만듬
+                tag.commit();
+              }
+            }
+          }
+        }
+      }
+    }
+
+    // 선택한 것이 있는지 확인
+    boolean needDefault = true;
+    for (FilterTagBean tagBean : tagBeans) {
+      if (tagBean.isSelected()) {
+        needDefault = false;
+        break;
+      }
+    }
+
+    // 처음 하나도 선택 안된 상태라면 '전체'를 기본값으로 선택한다.
+    if (needDefault) {
+      for (FilterTagBean tagBean : tagBeans) {
+        if (FilterTagBean.TAG_NO_TOTAL.equals(tagBean.getTagNo())) {
+          tagBean.setSelected(true);
+          // 사용자 선택 전이므로 commit 은 하지 않는다.
+          break;
+        }
+      }
+    }
+  }
+}

+ 37 - 7
app/src/main/java/kr/co/zumo/app/lifeplus/view/dialog/LoadingDialog.java

@@ -4,11 +4,16 @@
 package kr.co.zumo.app.lifeplus.view.dialog;
 
 import android.app.Dialog;
+import android.graphics.drawable.ColorDrawable;
 import android.os.Bundle;
 import android.support.annotation.NonNull;
-import android.support.v7.app.AlertDialog;
+import android.view.View;
+import android.view.Window;
+import android.view.WindowManager;
+import android.widget.ImageView;
 
 import kr.co.zumo.app.R;
+import kr.co.zumo.app.lifeplus.view.FrameAnimation;
 
 /**
  * LoadingDialog
@@ -22,20 +27,45 @@ import kr.co.zumo.app.R;
  */
 public class LoadingDialog extends DialogBase {
 
+  private ImageView imageView;
+  private FrameAnimation animation;
+
   @Override
   protected void onActivityCreatedInternal() {
-//    Window window = getDialog().getWindow();
-//    window.setLayout(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT);
-//    window.setBackgroundDrawable(new ColorDrawable(android.graphics.Color.TRANSPARENT));
+    Window window = getDialog().getWindow();
+    window.setLayout(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT);
+    window.setBackgroundDrawable(new ColorDrawable(android.graphics.Color.TRANSPARENT));
   }
 
-
   @NonNull
   @Override
   public Dialog onCreateDialog(Bundle savedInstanceState) {
-    android.support.v7.app.AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+//    android.support.v7.app.AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
     Dialog loadingDialog = super.onCreateDialog(savedInstanceState);
-    loadingDialog.setContentView(R.layout.dialog_loading);
+    View view = getActivity().getLayoutInflater().inflate(R.layout.dialog_loading, null);
+
+    loadingDialog.setContentView(view);
+    loadingDialog.setCancelable(false);
+
+    imageView = view.findViewById(R.id.image_loading);
+    imageView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+    animation = new FrameAnimation.Builder(imageView, R.array.loading_animation, 40).repeat(true).build();
+
     return loadingDialog;
   }
+
+  @Override
+  public void dispose() {
+
+    if (null != animation) {
+      animation.stopAnimation();
+      animation = null;
+    }
+    if (null != imageView) {
+      imageView.setLayerType(View.LAYER_TYPE_NONE, null);
+      imageView = null;
+    }
+
+    super.dispose();
+  }
 }

+ 117 - 143
app/src/main/java/kr/co/zumo/app/lifeplus/view/screen/category/CategoryFilterModel.java

@@ -27,6 +27,7 @@ import kr.co.zumo.app.lifeplus.model.module.APICategoryFilterDetailModule;
 import kr.co.zumo.app.lifeplus.model.module.APICategoryFilterModule;
 import kr.co.zumo.app.lifeplus.model.module.APIError;
 import kr.co.zumo.app.lifeplus.model.module.APIModuleListener;
+import kr.co.zumo.app.lifeplus.model.module.FilterDetailParser;
 import kr.co.zumo.app.lifeplus.util.StringUtil;
 import kr.co.zumo.app.lifeplus.view.Event;
 import kr.co.zumo.app.lifeplus.view.IEventListener;
@@ -143,12 +144,6 @@ public abstract class CategoryFilterModel extends CategoryMainModel {
 
   }
 
-  private boolean isFilterApplied = false;
-  private int listCount = 0;
-  private CategoryFilterContentsResultBean filterSearchResultBean;
-  private CategoryFilterContentsResultBean filterSearchResultBeanOnlyProperty;  // 지역/핫플 상세 필터를 요구할 때 이전 검색 결과를 제줄해야한다. 이는 지역/핫플이 적용되지 않은 필터 데이터를 갖고 있다.
-  private List<CategoryContentsBean> committedFilteringContents;
-
   /**
    * 검색 필터 데이터
    *
@@ -213,16 +208,18 @@ public abstract class CategoryFilterModel extends CategoryMainModel {
     });
   }
 
-  public void loadFilteringContents(IWaiterCallable waiterCallable, IEventListener listener) {
-    Log.w("APP# CategoryFilterModel | loadFilteringContents", "|" + " -------------------------- ");
+  private boolean isFilterApplied = false;
+  private int listCount = 0;
+  private CategoryFilterContentsResultBean filterSearchResultBean;
+  private CategoryItemNoProvider itemNoProvider = new CategoryItemNoProvider();
+  private List<CategoryContentsBean> committedFilteringContents;
 
-    CategoryFilterContentsRequestBean requestBean = new CategoryFilterContentsRequestBean(getCategoryNo());
+  public void loadFilteringContents(CategoryFilterContentsRequestBean requestBean, boolean hasFilter, IWaiterCallable waiterCallable, IEventListener listener) {
 
-    // 필터 적용
-    if (applyFilter(requestBean) == false) {
+    if (hasFilter == false) {
       isFilterApplied = false;
       filterSearchResultBean = null;
-      filterSearchResultBeanOnlyProperty = null;
+      itemNoProvider.reset();
       listCount = 0;
       listener.onEvent(new Event.Builder(Event.SUCCESS).integer(listCount).build());
       Log.d("APP# CategoryFilterModel | loadFilteringContents", "|" + "적용된 필터 없음.");
@@ -236,9 +233,11 @@ public abstract class CategoryFilterModel extends CategoryMainModel {
         if (null != filterSearchResultBean) {
           isFilterApplied = true;
           listCount = filterSearchResultBean.getListCount();
-          if (StringUtil.isEmpty(requestBean.getFilterArea()) && StringUtil.isEmpty(requestBean.getFilterPlace())) {
-            // 지역/핫플 필터가 없는 데이터는 별도 보관한다. 상세 필터를 요구할 때 이용 일치하는 결과가 없더라도 저장해야 맞음
-            filterSearchResultBeanOnlyProperty = filterSearchResultBean;
+          // 지역/핫플 필터가 없는 데이터는 별도 보관한다. 상세 필터를 요구할 때 이용, 일치하는 결과가 없더라도 저장해야 맞음
+          if (itemNoProvider.needSaving(requestBean)) {
+            Log.d("APP# CategoryFilterModel | onApiSuccess", "|" + " ********************** 기초 데이터 저장");
+            itemNoProvider.setRequestBean(requestBean);
+            itemNoProvider.setResult(filterSearchResultBean);
           }
 
           listener.onEvent(new Event.Builder(Event.SUCCESS).integer(listCount).build());
@@ -255,155 +254,68 @@ public abstract class CategoryFilterModel extends CategoryMainModel {
     });
   }
 
-  private boolean applyFilter(CategoryFilterContentsRequestBean requestBean) {
-    // 필터 추가
-    boolean isApplied = false;
-    if (null != filterSectionBeans) {
-      for (FilterSectionBean filterSectionBean : filterSectionBeans) {
-        for (FilterBean filterBean : filterSectionBean.getFilterBeans()) {
+  public void loadFilteringContents(IWaiterCallable waiterCallable, IEventListener listener) {
+    Log.w("APP# CategoryFilterModel | loadFilteringContents", "|" + " -------------------------- ");
 
-          if (FilterBean.hasChildValue(filterBean)) {
-            for (FilterTagBean tagBean : filterBean.getTagBeans()) {
-              if (tagBean.isSelected()) {
-                switch (filterBean.getFilterType()) {
-                  case FilterBean.FILTER_TYPE_AREA:
-                    isApplied = true;
-                    requestBean.setFilterArea(requestBean.getFilterArea() + StringUtil.HASH + tagBean.getTagNo());
-                    break;
-                  case FilterBean.FILTER_TYPE_HOT_PLACE:
-                    isApplied = true;
-                    requestBean.setFilterPlace(requestBean.getFilterPlace() + StringUtil.HASH + tagBean.getTagNo());
-                    break;
-                  default:
-                    break;
-                }
-              }
-            }
-          }
-          else if (filterBean.isSelected()) {
-            switch (filterBean.getFilterType()) {
-              case FilterBean.FILTER_TYPE_AREA:
-                isApplied = true;
-                requestBean.setFilterArea(requestBean.getFilterArea() + StringUtil.HASH + filterBean.getFilterNo());
-                break;
-              case FilterBean.FILTER_TYPE_HOT_PLACE:
-                isApplied = true;
-                requestBean.setFilterPlace(requestBean.getFilterPlace() + StringUtil.HASH + filterBean.getFilterNo());
-                break;
-              case FilterBean.FILTER_TYPE_PROPERTY:
-                isApplied = true;
-                requestBean.setFilter(requestBean.getFilter() + StringUtil.HASH + filterBean.getFilterNo());
-                break;
-              default:
-                break;
-            }
-          }
-        }
-      }
-    }
+    CategoryFilterContentsRequestBean requestBean = new CategoryFilterContentsRequestBean(getCategoryNo());
 
-    requestBean.setOrder(getCurrentSort());
+    // 필터 적용
+    boolean hasFilter = applyFilter(requestBean, false);
+
+    loadFilteringContents(requestBean, hasFilter, waiterCallable, listener);
 
-    // 필터 적용 됐음
-    return isApplied;
   }
 
-  public void loadFilterDetail(FilterBean filterBean, IFilterDetailListener listener) {
+  public void loadFilterDetail(FilterBean filterBean, IWaiterCallable waiterCallable, IFilterDetailListener listener) {
+    // itemNo base load
+    // 현재 필터 중 지역/핫풀 필터를 제외한 설정으로 로딩 후 디테일 가져옴
 
-    String type = filterBean.getFilterType();
-    String no = filterBean.getFilterNo();
-    StringBuilder itemNoes = new StringBuilder();
-
-    // 필터링 처리한 임시 데이터
-    List<CategoryContentsBean> targetList = null;
+    // 키워드는 변경 없음
+    CategoryFilterContentsRequestBean requestBean = new CategoryFilterContentsRequestBean(getCategoryNo());
 
+    // 필터 적용 -> 지역은 제외하고 필터 적용
+    boolean hasFilter = applyFilter(requestBean, true);
 
-    // 지역 필터 적용 이전의 데이터를 저장해두고 넘겨줘야 한다.
-    if (null != filterSearchResultBeanOnlyProperty) {
-      // 일치하는 결과가 있음.
-      if (null != filterSearchResultBeanOnlyProperty.getData() && filterSearchResultBeanOnlyProperty.getData().size() > 0) {
-        targetList = filterSearchResultBeanOnlyProperty.getData();
-      }
-      else {
-        // 다른 태그로 검색은 했지만 결과가 없음.
-        targetList = null;
-      }
+    if (itemNoProvider.hasResult(requestBean)) {
+      // 이미 동일한 결과가 있으면
+      Log.e("APP# CategoryFilterModel | loadFilterDetail", "|" + "********************************* 이전 기초 결과 이용");
+      loadFilterDetailInternal(filterBean, waiterCallable, listener);
     }
     else {
-      // 다른 태그로 검색한 적 없음
-      targetList = null;
+      Log.e("APP# CategoryFilterModel | loadFilterDetail", "|" + "********************************* 다시 기초 로드");
+      loadFilteringContents(requestBean, hasFilter, waiterCaller, event -> {
+        if (event.getEventId() == Event.SUCCESS) {
+          loadFilterDetailInternal(filterBean, waiterCallable, listener);
+        }
+        else if (event.getEventId() == Event.ERROR) {
+          listener.onError(filterBean);
+        }
+      });
     }
+  }
 
-    /*
-      디테일 정보를 요청할 경우 각 태그별로 컨텐츠 수를 표시하기 위해서 기 검색된 컨텐츠의 no 들을 함께 넘겨준다.
-     */
+  private void loadFilterDetailInternal(FilterBean filterBean, IWaiterCallable waiterCallable, IFilterDetailListener listener) {
+    String type = filterBean.getFilterType();
+    String no = filterBean.getFilterNo();
 
-    // 전송할 데이터가 있다면 추가
-    if (null != targetList && targetList.size() > 0) {
-      for (CategoryContentsBean contentsBean : targetList) {
-        if (null != contentsBean.getItemNo()) {
-          itemNoes.append(StringUtil.HASH).append(contentsBean.getItemNo());
-        }
-      }
+    // 필터링 처리한 임시 데이터
+    String itemNoes = itemNoProvider.getItemNoes(null);
+
+    // "" 으로 요청하면 결과가 맞지않아서 dummy 를 넣어줌
+    if (StringUtil.isEmpty(itemNoes)) {
+      itemNoes = "#0000";
     }
 
     disposableFilter = new APICategoryFilterDetailModule().call(
-      new CategoryFilterDetailRequestBean(getCategoryNo(), type, no, itemNoes.toString()),
-      new APIModuleListener<CategoryFilterDetailResultBean>(waiterCaller
-      ) {
+      new CategoryFilterDetailRequestBean(getCategoryNo(), type, no, itemNoes),
+      new APIModuleListener<CategoryFilterDetailResultBean>(waiterCallable) {
         @Override
         public void onApiSuccess(CategoryFilterDetailResultBean resultBean) {
           // 결과를 filterBean 에 맵핑 해준다.
           if (null != resultBean && null != resultBean.getData()) {
             List<FilterTagBean> tagBeans = resultBean.getData();
 
-            // todo filter bean 파서 추가 필요
-
-            // '전체' 태그는 tag no 를 'all' 로 변환
-            for (FilterTagBean tagBean : tagBeans) {
-              if (FilterTagBean.INDEX_TOTAL.equals(tagBean.getTagNo()) || FilterTagBean.TAG_NAME_TOTAL.equals(tagBean.getTagName())) {
-                tagBean.setTagNo(FilterTagBean.TAG_NO_TOTAL);
-                break;
-              }
-            }
-
-            // 이전 선택한 항목 재 선택
-            if (null != filterBean.getTagBeans()) {
-              for (FilterTagBean before : filterBean.getTagBeans()) {
-                String tagNo = before.getTagNo();
-                if (StringUtil.isFull(tagNo)) {
-                  for (FilterTagBean tag : tagBeans) {
-                    if (tagNo.equals(tag.getTagNo())) {
-                      tag.setSelected(before.isSelected());
-                      if (before.canCommit() == false) {
-                        // 커밋한 상태로 만듬
-                        tag.commit();
-                      }
-                    }
-                  }
-                }
-              }
-            }
-
-            // 선택한 것이 있는지 확인
-            boolean needDefault = true;
-            for (FilterTagBean tagBean : tagBeans) {
-              if (tagBean.isSelected()) {
-                needDefault = false;
-                break;
-              }
-            }
-
-            // 처음 하나도 선택 안된 상태라면 '전체'를 기본값으로 선택한다.
-            if (needDefault) {
-              for (FilterTagBean tagBean : tagBeans) {
-                if (FilterTagBean.TAG_NO_TOTAL.equals(tagBean.getTagNo())) {
-                  tagBean.setSelected(true);
-                  // 사용자 선택 전이므로 commit 은 하지 않는다.
-                  break;
-                }
-              }
-            }
+            new FilterDetailParser().parse(filterBean, tagBeans);
 
             filterBean.setTagBeans(tagBeans);
           }
@@ -429,6 +341,68 @@ public abstract class CategoryFilterModel extends CategoryMainModel {
   }
 
 
+  private boolean applyFilter(CategoryFilterContentsRequestBean requestBean, boolean withoutArea) {
+    // 필터 추가
+    boolean isApplied = false;
+    if (null != filterSectionBeans) {
+      for (FilterSectionBean filterSectionBean : filterSectionBeans) {
+        for (FilterBean filterBean : filterSectionBean.getFilterBeans()) {
+
+          if (FilterBean.hasChildValue(filterBean)) {
+            for (FilterTagBean tagBean : filterBean.getTagBeans()) {
+              if (tagBean.isSelected()) {
+                switch (filterBean.getFilterType()) {
+                  case FilterBean.FILTER_TYPE_AREA:
+                    if (false == withoutArea) {
+                      isApplied = true;
+                      requestBean.setFilterArea(requestBean.getFilterArea() + StringUtil.HASH + tagBean.getTagNo());
+                    }
+                    break;
+                  case FilterBean.FILTER_TYPE_HOT_PLACE:
+                    if (false == withoutArea) {
+                      isApplied = true;
+                      requestBean.setFilterPlace(requestBean.getFilterPlace() + StringUtil.HASH + tagBean.getTagNo());
+                    }
+                    break;
+                  default:
+                    break;
+                }
+              }
+            }
+          }
+          else if (filterBean.isSelected()) {
+            switch (filterBean.getFilterType()) {
+              case FilterBean.FILTER_TYPE_AREA:
+                if (false == withoutArea) {
+                  isApplied = true;
+                  requestBean.setFilterArea(requestBean.getFilterArea() + StringUtil.HASH + filterBean.getFilterNo());
+                }
+                break;
+              case FilterBean.FILTER_TYPE_HOT_PLACE:
+                if (false == withoutArea) {
+                  isApplied = true;
+                  requestBean.setFilterPlace(requestBean.getFilterPlace() + StringUtil.HASH + filterBean.getFilterNo());
+                }
+                break;
+              case FilterBean.FILTER_TYPE_PROPERTY:
+                isApplied = true;
+                requestBean.setFilter(requestBean.getFilter() + StringUtil.HASH + filterBean.getFilterNo());
+                break;
+              default:
+                break;
+            }
+          }
+        }
+      }
+    }
+
+    requestBean.setOrder(getCurrentSort());
+
+    // 필터 적용 됐음
+    return isApplied;
+  }
+
+
   private String getCurrentSort() {
     /*
     01 : 날짜순,  02 : 북마크순, 03 : 좋아요순
@@ -496,7 +470,7 @@ public abstract class CategoryFilterModel extends CategoryMainModel {
    */
   public void resetFilter() {
     isFilterApplied = false;
-    filterSearchResultBeanOnlyProperty = null;
+    itemNoProvider.reset();
     listCount = 0;
 
     int len = filterSectionBeans.size();

+ 35 - 1
app/src/main/java/kr/co/zumo/app/lifeplus/view/screen/category/CategoryFilterPresenter.java

@@ -5,11 +5,14 @@ import android.util.Log;
 
 import kr.co.zumo.app.lifeplus.bean.api.FilterBean;
 import kr.co.zumo.app.lifeplus.view.Event;
+import kr.co.zumo.app.lifeplus.view.IWaiterCallable;
 import kr.co.zumo.app.lifeplus.view.dialog.DialogBuilder;
 import kr.co.zumo.app.lifeplus.view.dialog.DialogID;
 import kr.co.zumo.app.lifeplus.view.dialog.FilterDialog;
+import kr.co.zumo.app.lifeplus.view.dialog.ICustomDialogListener;
 import kr.co.zumo.app.lifeplus.view.dialog.IFilterDetailListener;
 import kr.co.zumo.app.lifeplus.view.dialog.IFilterListener;
+import kr.co.zumo.app.lifeplus.view.dialog.LoadingDialog;
 
 /**
  * CategoryFilterPresenter
@@ -24,11 +27,18 @@ import kr.co.zumo.app.lifeplus.view.dialog.IFilterListener;
 public abstract class CategoryFilterPresenter<M extends CategoryFilterModel, V extends ICategoryMainView> extends CategoryMainPresenter<M, V> {
 
   private FilterDialog filterDialog;
+  private LoadingDialog filterWaiter;
 
   public CategoryFilterPresenter(M model, V view) {
     super(model, view);
   }
 
+  @Override
+  protected void destroyInternal() {
+    super.destroyInternal();
+    hideFilterWaiter();
+  }
+
   @CallSuper
   @Override
   protected void onCategoryEvent(Event event) {
@@ -89,7 +99,17 @@ public abstract class CategoryFilterPresenter<M extends CategoryFilterModel, V e
           @Override
           public void onFilterDetail(FilterDialog dialog, FilterBean filterBean) {
             // 필터 세부 항목 요청
-            model.loadFilterDetail(filterBean, new IFilterDetailListener() {
+            model.loadFilterDetail(filterBean, new IWaiterCallable() {
+              @Override
+              public void showWaiter() {
+                showFilterWaiter();
+              }
+
+              @Override
+              public void hideWaiter() {
+                hideFilterWaiter();
+              }
+            }, new IFilterDetailListener() {
               @Override
               public void onCompleted(FilterBean filterBean) {
                 dialog.setFilterDetail(filterBean);
@@ -151,4 +171,18 @@ public abstract class CategoryFilterPresenter<M extends CategoryFilterModel, V e
   protected void onScreenReadyInternal() {
 
   }
+
+  private void showFilterWaiter() {
+    if (null == filterWaiter) {
+      filterWaiter = new DialogBuilder<LoadingDialog, ICustomDialogListener>(getFragmentManager(), DialogID.LOADING)
+        .show();
+    }
+  }
+
+  private void hideFilterWaiter() {
+    if (null != filterWaiter) {
+      filterWaiter.dispose();
+      filterWaiter = null;
+    }
+  }
 }

+ 143 - 0
app/src/main/java/kr/co/zumo/app/lifeplus/view/screen/category/CategoryItemNoProvider.java

@@ -0,0 +1,143 @@
+/*
+ * COPYRIGHT (c) 2018 All rights reserved by HANWHA LIFE.
+ */
+package kr.co.zumo.app.lifeplus.view.screen.category;
+
+import android.support.annotation.Nullable;
+
+import java.util.List;
+
+import kr.co.zumo.app.lifeplus.bean.api.CategoryContentsBean;
+import kr.co.zumo.app.lifeplus.bean.api.CategoryFilterContentsRequestBean;
+import kr.co.zumo.app.lifeplus.bean.api.CategoryFilterContentsResultBean;
+import kr.co.zumo.app.lifeplus.util.StringUtil;
+import kr.co.zumo.app.lifeplus.view.screen.search.IItemNoProvider;
+
+/**
+ * CategoryItemNoProvider
+ * <pre>
+ * </pre>
+ *
+ * @author 민효동
+ * @version 1.0
+ * @history 민효동   [2019. 2. 27.]   [최초 작성]
+ * @since 2019. 2. 27.
+ */
+public class CategoryItemNoProvider implements IItemNoProvider<CategoryFilterContentsRequestBean, CategoryContentsBean, CategoryFilterContentsResultBean> {
+
+  private CategoryFilterContentsResultBean contentsResultBean;  // 지역/핫플 상세 필터를 요구할 때 이전 검색 결과를 제줄해야한다. 이는 지역/핫플이 적용되지 않은 필터 데이터를 갖고 있다.
+
+  private CategoryFilterContentsRequestBean contentsRequestBean;
+
+  /**
+   * 상세 필터에 기본 itemNo 를 추가하기
+   *
+   * @param initList
+   * @return
+   */
+  public String getItemNoes(@Nullable List<CategoryContentsBean> initList) {
+    StringBuilder itemNoes = new StringBuilder();
+
+    List<CategoryContentsBean> targetList = initList;
+
+    // 지역 필터 적용 이전의 데이터를 저장해두고 넘겨줘야 한다.
+    if (null != contentsResultBean) {
+
+      // 일치하는 결과가 있음.
+      if (null != contentsResultBean.getData() && contentsResultBean.getData().size() > 0) {
+        targetList = contentsResultBean.getData();
+      }
+      else {
+        // 다른 태그로 검색은 했지만 결과가 없음.
+        targetList = null;
+      }
+    }
+    else {
+      targetList = null;
+    }
+
+    // 전송할 데이터가 있다면 추가
+    if (null != targetList && targetList.size() > 0) {
+      for (CategoryContentsBean contentsBean : targetList) {
+        if (null != contentsBean.getItemNo()) {
+          itemNoes.append(StringUtil.HASH).append(contentsBean.getItemNo());
+        }
+      }
+    }
+
+    return itemNoes.toString();
+  }
+
+  /**
+   * 검색 결과 중 상세 필터 조회에 이용될 기초 데이터롤 이용할 것인지 확인
+   *
+   * @param requestBean
+   * @return
+   */
+  public boolean needSaving(CategoryFilterContentsRequestBean requestBean) {
+    if (StringUtil.isEmpty(requestBean.getFilterArea()) && StringUtil.isEmpty(requestBean.getFilterPlace())) {
+      // 지역/핫플 필터가 없는 데이터는 별도 보관한다. 상세 필터를 요구할 때 이용, 일치하는 결과가 없더라도 저장해야 맞음
+      return true;
+    }
+
+    return false;
+  }
+
+  /**
+   * @param resultBean
+   */
+  public void setResult(CategoryFilterContentsResultBean resultBean) {
+    contentsResultBean = resultBean;
+  }
+
+  /**
+   * 초기 상태로 돌림
+   */
+  public void reset() {
+    contentsResultBean = null;
+  }
+
+  /**
+   * 최근 요청 내용 저장
+   *
+   * @param requestBean
+   */
+  public void setRequestBean(CategoryFilterContentsRequestBean requestBean) {
+    this.contentsRequestBean = requestBean;
+  }
+
+
+  /**
+   * 이전 결과를 이용할 수 있는 데이터인지 확인
+   *
+   * @param requestBean
+   * @return
+   */
+  public boolean hasResult(CategoryFilterContentsRequestBean requestBean) {
+    if (null == contentsResultBean) {
+      return false;
+    }
+
+    if (null == contentsRequestBean || StringUtil.isEmpty(contentsRequestBean.getCategoryNo())) {
+      return false;
+    }
+
+    if (null == requestBean || StringUtil.isEmpty(requestBean.getCategoryNo())) {
+      return false;
+    }
+
+    if (contentsRequestBean.getFilter().equals(requestBean.getFilter()) == false) {
+      return false;
+    }
+
+    if (contentsRequestBean.getCategoryNo().equals(requestBean.getCategoryNo()) == false) {
+      return false;
+    }
+
+    if (contentsRequestBean.getOrder().equals(requestBean.getOrder()) == false) {
+      return false;
+    }
+
+    return true;
+  }
+}

+ 61 - 0
app/src/main/java/kr/co/zumo/app/lifeplus/view/screen/search/IItemNoProvider.java

@@ -0,0 +1,61 @@
+/*
+ * COPYRIGHT (c) 2018 All rights reserved by HANWHA LIFE.
+ */
+package kr.co.zumo.app.lifeplus.view.screen.search;
+
+import android.support.annotation.Nullable;
+
+import java.util.List;
+
+/**
+ * IItemNoProvider
+ * <pre>
+ * </pre>
+ *
+ * @author 민효동
+ * @version 1.0
+ * @history 민효동   [2019. 2. 27.]   [최초 작성]
+ * @since 2019. 2. 27.
+ */
+public interface IItemNoProvider<Q, L, R> {
+  /**
+   * 상세 필터에 기본 itemNo 를 추가하기
+   *
+   * @param initList
+   * @return
+   */
+  String getItemNoes(@Nullable List<L> initList);
+
+  /**
+   * 검색 결과 중 상세 필터 조회에 이용될 기초 데이터롤 이용할 것인지 확인
+   *
+   * @param requestBean
+   * @return
+   */
+  boolean needSaving(Q requestBean);
+
+  /**
+   * @param searchResultBean
+   */
+  void setResult(R searchResultBean);
+
+  /**
+   * 초기 상태로 돌림
+   */
+  void reset();
+
+  /**
+   * 최근 요청 내용 저장
+   *
+   * @param requestBean
+   */
+  void setRequestBean(Q requestBean);
+
+  /**
+   * 이전 결과를 이용할 수 있는 데이터인지 확인
+   *
+   * @param requestBean
+   * @return
+   */
+  boolean hasResult(Q requestBean);
+}

+ 153 - 0
app/src/main/java/kr/co/zumo/app/lifeplus/view/screen/search/SearchItemNoProvider.java

@@ -0,0 +1,153 @@
+/*
+ * COPYRIGHT (c) 2018 All rights reserved by HANWHA LIFE.
+ */
+package kr.co.zumo.app.lifeplus.view.screen.search;
+
+import android.support.annotation.Nullable;
+
+import java.util.List;
+
+import kr.co.zumo.app.lifeplus.bean.api.SearchContentsBean;
+import kr.co.zumo.app.lifeplus.bean.api.SearchRequestBean;
+import kr.co.zumo.app.lifeplus.bean.api.SearchResultBean;
+import kr.co.zumo.app.lifeplus.util.StringUtil;
+
+/**
+ * SearchItemNoProvider
+ * <pre>
+ * </pre>
+ *
+ * @author 민효동
+ * @version 1.0
+ * @history 민효동   [2019. 2. 27.]   [최초 작성]
+ * @since 2019. 2. 27.
+ */
+public class SearchItemNoProvider implements IItemNoProvider<SearchRequestBean, SearchContentsBean, SearchResultBean> {
+
+  private SearchResultBean contentsResultBean;  // 지역/핫플 상세 필터를 요구할 때 이전 검색 결과를 제줄해야한다. 이는 지역/핫플이 적용되지 않은 필터 데이터를 갖고 있다.
+
+  private SearchRequestBean searchRequestBean;
+
+  /**
+   * 상세 필터에 기본 itemNo 를 추가하기
+   *
+   * @param initList
+   * @return
+   */
+  public String getItemNoes(@Nullable List<SearchContentsBean> initList) {
+    StringBuilder itemNoes = new StringBuilder();
+
+    List<SearchContentsBean> targetList = initList;
+
+    // 지역 필터 적용 이전의 데이터를 저장해두고 넘겨줘야 한다.
+    if (null != contentsResultBean) {
+      // 일단 다른 태그로 검색한 상태임
+
+      // 결과 중 일치하는 콘텐츠 있음.
+      if (null != contentsResultBean.getTagBeans() && contentsResultBean.getTagBeans().size() > 0) {
+        if (null != contentsResultBean.getData() && contentsResultBean.getData().size() > 0) {
+          // 최종 콘텐츠 있음.
+          targetList = contentsResultBean.getData();
+        }
+        else {
+          // 태그는 일치하지만 콘텐츠는 없음.
+          targetList = null;
+        }
+      }
+      else {
+        // 일치하는 태그 없음(검색 결과 없음)
+        targetList = null;
+      }
+    }
+
+    // 전송할 데이터가 있다면 추가
+    if (null != targetList && targetList.size() > 0) {
+      for (SearchContentsBean contentsBean : targetList) {
+        if (null != contentsBean.getItemNo()) {
+          itemNoes.append(StringUtil.HASH).append(contentsBean.getItemNo());
+        }
+      }
+    }
+
+    return itemNoes.toString();
+  }
+
+  /**
+   * 검색 결과 중 상세 필터 조회에 이용될 기초 데이터롤 이용할 것인지 확인
+   *
+   * @param requestBean
+   * @return
+   */
+  public boolean needSaving(SearchRequestBean requestBean) {
+    if (StringUtil.isEmpty(requestBean.getFilterArea()) && StringUtil.isEmpty(requestBean.getFilterPlace())) {
+      // 지역/핫플 필터가 없는 데이터는 별도 보관한다. 상세 필터를 요구할 때 이용, 일치하는 결과가 없더라도 저장해야 맞음
+      return true;
+    }
+
+    return false;
+  }
+
+  /**
+   *
+   *
+   * @param searchResultBean
+   */
+  public void setResult(SearchResultBean searchResultBean) {
+    contentsResultBean = searchResultBean;
+  }
+
+  /**
+   * 초기 상태로 돌림
+   */
+  public void reset() {
+    contentsResultBean = null;
+  }
+
+  /**
+   * 최근 요청 내용 저장
+   *
+   * @param requestBean
+   */
+  public void setRequestBean(SearchRequestBean requestBean) {
+    this.searchRequestBean = requestBean;
+  }
+
+
+  /**
+   * 이전 결과를 이용할 수 있는 데이터인지 확인
+   *
+   * @param requestBean
+   * @return
+   */
+  public boolean hasResult(SearchRequestBean requestBean) {
+    if (null == contentsResultBean) {
+      return false;
+    }
+
+    if (null == searchRequestBean || StringUtil.isEmpty(searchRequestBean.getKeyword())) {
+      return false;
+    }
+
+    if (null == requestBean || StringUtil.isEmpty(requestBean.getKeyword())) {
+      return false;
+    }
+
+    if (searchRequestBean.getKeyword().equals(requestBean.getKeyword()) == false) {
+      return false;
+    }
+
+    if (searchRequestBean.getFilter().equals(requestBean.getFilter()) == false) {
+      return false;
+    }
+
+    if (searchRequestBean.getCategoryNo().equals(requestBean.getCategoryNo()) == false) {
+      return false;
+    }
+
+    if (searchRequestBean.getOrder().equals(requestBean.getOrder()) == false) {
+      return false;
+    }
+
+    return true;
+  }
+}

+ 106 - 129
app/src/main/java/kr/co/zumo/app/lifeplus/view/screen/search/SearchResultModel.java

@@ -38,6 +38,7 @@ import kr.co.zumo.app.lifeplus.model.module.APIModuleListener;
 import kr.co.zumo.app.lifeplus.model.module.APISearchFilterDetailModule;
 import kr.co.zumo.app.lifeplus.model.module.APISearchFilterModule;
 import kr.co.zumo.app.lifeplus.model.module.APISearchModule;
+import kr.co.zumo.app.lifeplus.model.module.FilterDetailParser;
 import kr.co.zumo.app.lifeplus.supervisor.ContentsFlagHelper;
 import kr.co.zumo.app.lifeplus.util.ResourceUtil;
 import kr.co.zumo.app.lifeplus.util.StringUtil;
@@ -169,7 +170,7 @@ public class SearchResultModel extends Model {
     }
 
     // 필터 적용
-    applyFilter(requestBean);
+    applyFilter(requestBean, false);
 
     Log.i("APP# SearchResultModel | search", "|" + " search ---> " + requestBean.toJson());
 
@@ -261,7 +262,7 @@ public class SearchResultModel extends Model {
     }
 
     // 필터 적용
-    applyFilter(requestBean);
+    applyFilter(requestBean, false);
 
     Log.d("APP# SearchResultModel | search", "|" + " search ---> " + requestBean.toJson());
 
@@ -637,51 +638,41 @@ public class SearchResultModel extends Model {
   }
 
   private SearchResultBean filterSearchResultBean;
-  private SearchResultBean filterSearchResultBeanOnlyProperty;  // 지역/핫플 상세 필터를 요구할 때 이전 검색 결과를 제줄해야한다. 이는 지역/핫플이 적용되지 않은 필터 데이터를 갖고 있다.
+  private SearchItemNoProvider itemNoProvider = new SearchItemNoProvider();
   private List<FilterSectionBean> filterSectionBeans;
 
   public final List<FilterSectionBean> getFilterList() {
     return filterSectionBeans;
   }
 
-  public void loadFilteringContents(IWaiterCallable waiterCallable, IEventListener listener) {
-    Log.w("APP# SearchResultModel | loadFilteringContents", "|" + " -------------------------- ");
-
-    // 키워드는 변경 없음
-    SearchRequestBean requestBean = new SearchRequestBean(getSearchTag());
-
-    // 카테고리 변경 없음.
-    if (null != categoryCheckBeans && categoryCheckBeans.size() > 0) {
-      CategoryCheckBean categoryCheckBean = categoryCheckBeans.get(selectedCategoryIndex);
-      if (null != categoryCheckBean) {
-        requestBean.setCategoryNo(categoryCheckBean.getCategoryNo());
-      }
-    }
-
-    // 필터 적용
-    boolean hasFilter = applyFilter(requestBean);
+  private void loadFilteringContentsInternal(SearchRequestBean requestBean, boolean hasFilter, IWaiterCallable waiterCallable, IEventListener listener) {
     if (hasFilter == false) {
-      Log.d("APP# SearchResultModel | loadFilteringContents", "|" + " 선택 필터 없음 -> 필터 없이 로딩 - 리스트 수 반환");
+      Log.d("APP# SearchResultModel | loadFilteringContentsInternal", "|" + " 선택 필터 없음 -> 필터 없이 로딩 - 리스트 수 반환");
     }
 
-    Log.i("APP# SearchResultModel | loadFilteringContents", "|" + " search ---> " + requestBean.toJson());
+    Log.i("APP# SearchResultModel | loadFilteringContentsInternal", "|" + " search ---> " + requestBean.toJson());
     if (StringUtil.isEmpty(requestBean.getKeyword())) {
-      Log.i("APP# SearchResultModel | loadFilteringContents", "|" + " 검색어 없음.");
-      filterSearchResultBeanOnlyProperty = null;
+      Log.d("APP# SearchResultModel | loadFilteringContentsInternal", "|" + " 검색어 없음.");
+      itemNoProvider.reset();
       return;
     }
 
+    stopSearch();
     disposableSearch = new APISearchModule().call(requestBean, new APIModuleListener<SearchResultBean>(waiterCallable) {
       @Override
       public void onApiSuccess(SearchResultBean resultBean) {
         filterSearchResultBean = resultBean;
         if (null != filterSearchResultBean) {
-          if (StringUtil.isEmpty(requestBean.getFilterArea()) && StringUtil.isEmpty(requestBean.getFilterPlace())) {
-            // 지역/핫플 필터가 없는 데이터는 별도 보관한다. 상세 필터를 요구할 때 이용, 일치하는 결과가 없더라도 저장해야 맞음
-            filterSearchResultBeanOnlyProperty = filterSearchResultBean;
+
+          // 지역/핫플 필터가 없는 데이터는 별도 보관한다. 상세 필터를 요구할 때 이용, 일치하는 결과가 없더라도 저장해야 맞음
+          if (itemNoProvider.needSaving(requestBean)) {
+            Log.d("APP# SearchResultModel | onApiSuccess", "|" + " ********************** 기초 데이터 저장");
+            itemNoProvider.setRequestBean(requestBean);
+            itemNoProvider.setResult(filterSearchResultBean);
           }
 
           isFilterApplied = hasFilter;
+          Log.i("APP# SearchResultModel | onApiSuccess", "|" + " isFilterApplied: " + isFilterApplied);
           int count = filterSearchResultBean.getListCount();
           if (null == filterSearchResultBean.getTagBeans() || filterSearchResultBean.getTagBeans().size() == 0) {
             count = 0;
@@ -700,119 +691,97 @@ public class SearchResultModel extends Model {
     });
   }
 
-  public void loadFilterDetail(FilterBean filterBean, IFilterDetailListener listener) {
+  private SearchRequestBean getSearchRequestBean() {
+    // 키워드는 변경 없음
+    SearchRequestBean requestBean = new SearchRequestBean(getSearchTag());
 
-    String type = filterBean.getFilterType();
-    String no = filterBean.getFilterNo();
-    StringBuilder itemNoes = new StringBuilder();
+    // 카테고리 변경 없음.
+    if (null != categoryCheckBeans && categoryCheckBeans.size() > 0) {
+      CategoryCheckBean categoryCheckBean = categoryCheckBeans.get(selectedCategoryIndex);
+      if (null != categoryCheckBean) {
+        requestBean.setCategoryNo(categoryCheckBean.getCategoryNo());
+      }
+    }
 
-    // 필터링 처리한 임시 데이터
-    List<SearchContentsBean> targetList = resultContentsBeansFirst;  // 우선 초기 데이터로 지정
+    return requestBean;
+  }
 
-    // 지역 필터 적용 이전의 데이터를 저장해두고 넘겨줘야 한다.
-    if (null != filterSearchResultBeanOnlyProperty) {
-      // 일단 다른 태그로 검색한 상태임
+  public void loadFilteringContents(IWaiterCallable waiterCallable, IEventListener listener) {
+    Log.i("APP# SearchResultModel | loadFilteringContentsInternal", "|" + " -------------------------- ");
+
+    // 키워드는 변경 없음
+    SearchRequestBean requestBean = getSearchRequestBean();
+
+    // 필터 적용
+    boolean hasFilter = applyFilter(requestBean, false);
 
-      // 결과 중 일치하는 콘텐츠 있음.
-      if (null != filterSearchResultBeanOnlyProperty.getTagBeans() && filterSearchResultBeanOnlyProperty.getTagBeans().size() > 0) {
-        if (null != filterSearchResultBeanOnlyProperty.getData() && filterSearchResultBeanOnlyProperty.getData().size() > 0) {
-          // 최종 콘텐츠 있음.
-          targetList = filterSearchResultBeanOnlyProperty.getData();
+    loadFilteringContentsInternal(requestBean, hasFilter, waiterCallable, listener);
+  }
+
+  public void loadFilterDetail(FilterBean filterBean, IWaiterCallable waiterCallable, IFilterDetailListener listener) {
+    // itemNo base load
+    // 현재 필터 중 지역/핫풀 필터를 제외한 설정으로 로딩 후 디테일 가져옴
+
+    // 키워드는 변경 없음
+    SearchRequestBean requestBean = getSearchRequestBean();
+
+    // 필터 적용 -> 지역은 제외하고 필터 적용
+    boolean hasFilter = applyFilter(requestBean, true);
+
+    if (itemNoProvider.hasResult(requestBean)) {
+      // 이미 동일한 결과가 있으면
+      Log.e("APP# SearchResultModel | loadFilterDetail", "|" + "********************************* 이전 기초 결과 이용");
+      loadFilterDetailInternal(filterBean, waiterCallable, listener);
+    }
+    else {
+      Log.e("APP# SearchResultModel | loadFilterDetail", "|" + "********************************* 다시 기초 로드");
+      loadFilteringContentsInternal(requestBean, hasFilter, waiterCallable, event -> {
+        if (event.getEventId() == Event.SUCCESS) {
+          loadFilterDetailInternal(filterBean, waiterCallable, listener);
         }
-        else {
-          // 태그는 일치하지만 콘텐츠는 없음.
-          targetList = null;
+        else if (event.getEventId() == Event.ERROR) {
+          listener.onError(filterBean);
         }
-      }
-      else {
-        // 일치하는 태그 없음(검색 결과 없음)
-        targetList = null;
-      }
+      });
     }
+  }
 
-    /*
-      디테일 정보를 요청할 경우 각 태그별로 컨텐츠 수를 표시하기 위해서 기 검색된 컨텐츠의 no 들을 함께 넘겨준다.
-     */
+  private void loadFilterDetailInternal(FilterBean filterBean, IWaiterCallable waiterCallable, IFilterDetailListener listener) {
+    String type = filterBean.getFilterType();
+    String no = filterBean.getFilterNo();
 
-    // 전송할 데이터가 있다면 추가
-    if (null != targetList && targetList.size() > 0) {
-      for (SearchContentsBean contentsBean : targetList) {
-        if (null != contentsBean.getItemNo()) {
-          itemNoes.append(StringUtil.HASH).append(contentsBean.getItemNo());
-        }
-      }
+    String itemNoes = itemNoProvider.getItemNoes(resultContentsBeansFirst);
+
+    // "" 으로 요청하면 결과가 맞지않아서 dummy 를 넣어줌
+    if (StringUtil.isEmpty(itemNoes)) {
+      itemNoes = "#0000";
     }
 
-    disposableFilter = new APISearchFilterDetailModule().call(new FilterDetailRequestBean(type, no, itemNoes.toString()), new APIModuleListener<SearchFilterDetailResultBean>(waiterCaller) {
-      @Override
-      public void onApiSuccess(SearchFilterDetailResultBean resultBean) {
-        // 결과를 filterBean 에 맵핑 해준다.
-        if (null != resultBean && null != resultBean.getData()) {
-          List<FilterTagBean> tagBeans = resultBean.getData();
-
-          // todo filter bean 파서 추가 필요
-
-          // '전체' 태그는 tag no 를 'all' 로 변환
-          for (FilterTagBean tagBean : tagBeans) {
-            if (FilterTagBean.INDEX_TOTAL.equals(tagBean.getTagNo()) || FilterTagBean.TAG_NAME_TOTAL.equals(tagBean.getTagName())) {
-              tagBean.setTagNo(FilterTagBean.TAG_NO_TOTAL);
-              break;
-            }
-          }
+    disposableFilter = new APISearchFilterDetailModule().call(
+      new FilterDetailRequestBean(type, no, itemNoes),
+      new APIModuleListener<SearchFilterDetailResultBean>(waiterCallable) {
+        @Override
+        public void onApiSuccess(SearchFilterDetailResultBean resultBean) {
+          // 결과를 filterBean 에 맵핑 해준다.
+          if (null != resultBean && null != resultBean.getData()) {
+            List<FilterTagBean> tagBeans = resultBean.getData();
 
-          // 이전 선택한 항목 재 선택
-          if (null != filterBean.getTagBeans()) {
-            for (FilterTagBean before : filterBean.getTagBeans()) {
-              String tagNo = before.getTagNo();
-              if (StringUtil.isFull(tagNo)) {
-                for (FilterTagBean tag : tagBeans) {
-                  if (tagNo.equals(tag.getTagNo())) {
-                    tag.setSelected(before.isSelected());
-                    if (before.canCommit() == false) {
-                      // 커밋한 상태로 만듬
-                      tag.commit();
-                    }
-                  }
-                }
-              }
-            }
-          }
+            new FilterDetailParser().parse(filterBean, tagBeans);
 
-          // 선택한 것이 있는지 확인
-          boolean needDefault = true;
-          for (FilterTagBean tagBean : tagBeans) {
-            if (tagBean.isSelected()) {
-              needDefault = false;
-              break;
-            }
+            filterBean.setTagBeans(tagBeans);
           }
 
-          // 처음 하나도 선택 안된 상태라면 '전체'를 기본값으로 선택한다.
-          if (needDefault) {
-            for (FilterTagBean tagBean : tagBeans) {
-              if (FilterTagBean.TAG_NO_TOTAL.equals(tagBean.getTagNo())) {
-                tagBean.setSelected(true);
-                // 사용자 선택 전이므로 commit 은 하지 않는다.
-                break;
-              }
-            }
-          }
-
-          filterBean.setTagBeans(tagBeans);
+          listener.onCompleted(filterBean);
         }
 
-        listener.onCompleted(filterBean);
-      }
-
-      @Override
-      public void onApiError(String errorMessage, APIError error) {
-        listener.onError(filterBean);
-      }
-    });
+        @Override
+        public void onApiError(String errorMessage, APIError error) {
+          listener.onError(filterBean);
+        }
+      });
   }
 
-
-  private boolean applyFilter(SearchRequestBean requestBean) {
+  private boolean applyFilter(SearchRequestBean requestBean, boolean withoutArea) {
     // 필터 추가
     boolean isApplied = false;
     if (null != filterSectionBeans) {
@@ -824,12 +793,16 @@ public class SearchResultModel extends Model {
               if (tagBean.isSelected()) {
                 switch (filterBean.getFilterType()) {
                   case FilterBean.FILTER_TYPE_AREA:
-                    isApplied = true;
-                    requestBean.setFilterArea(requestBean.getFilterArea() + StringUtil.HASH + tagBean.getTagNo());
+                    if (false == withoutArea) {
+                      isApplied = true;
+                      requestBean.setFilterArea(requestBean.getFilterArea() + StringUtil.HASH + tagBean.getTagNo());
+                    }
                     break;
                   case FilterBean.FILTER_TYPE_HOT_PLACE:
-                    isApplied = true;
-                    requestBean.setFilterPlace(requestBean.getFilterPlace() + StringUtil.HASH + tagBean.getTagNo());
+                    if (false == withoutArea) {
+                      isApplied = true;
+                      requestBean.setFilterPlace(requestBean.getFilterPlace() + StringUtil.HASH + tagBean.getTagNo());
+                    }
                     break;
                   default:
                     break;
@@ -840,12 +813,16 @@ public class SearchResultModel extends Model {
           else if (filterBean.isSelected()) {
             switch (filterBean.getFilterType()) {
               case FilterBean.FILTER_TYPE_AREA:
-                isApplied = true;
-                requestBean.setFilterArea(requestBean.getFilterArea() + StringUtil.HASH + filterBean.getFilterNo());
+                if (false == withoutArea) {
+                  isApplied = true;
+                  requestBean.setFilterArea(requestBean.getFilterArea() + StringUtil.HASH + filterBean.getFilterNo());
+                }
                 break;
               case FilterBean.FILTER_TYPE_HOT_PLACE:
-                isApplied = true;
-                requestBean.setFilterPlace(requestBean.getFilterPlace() + StringUtil.HASH + filterBean.getFilterNo());
+                if (false == withoutArea) {
+                  isApplied = true;
+                  requestBean.setFilterPlace(requestBean.getFilterPlace() + StringUtil.HASH + filterBean.getFilterNo());
+                }
                 break;
               case FilterBean.FILTER_TYPE_ORDER:
                 if (filterBean.getFilterNo().equals(FilterBean.FILTER_ORDER_LATEST) == false) {
@@ -934,7 +911,7 @@ public class SearchResultModel extends Model {
     }
 
     filterSearchResultBean = null;
-    filterSearchResultBeanOnlyProperty = null;
+    itemNoProvider.reset();
     isFilterApplied = false;
 
     int len = filterSectionBeans.size();

+ 30 - 2
app/src/main/java/kr/co/zumo/app/lifeplus/view/screen/search/SearchResultPresenter.java

@@ -13,11 +13,14 @@ import kr.co.zumo.app.lifeplus.bean.api.SearchContentsBean;
 import kr.co.zumo.app.lifeplus.supervisor.ScreenID;
 import kr.co.zumo.app.lifeplus.view.DoubleChecker;
 import kr.co.zumo.app.lifeplus.view.Event;
+import kr.co.zumo.app.lifeplus.view.IWaiterCallable;
 import kr.co.zumo.app.lifeplus.view.dialog.DialogBuilder;
 import kr.co.zumo.app.lifeplus.view.dialog.DialogID;
 import kr.co.zumo.app.lifeplus.view.dialog.FilterDialog;
+import kr.co.zumo.app.lifeplus.view.dialog.ICustomDialogListener;
 import kr.co.zumo.app.lifeplus.view.dialog.IFilterDetailListener;
 import kr.co.zumo.app.lifeplus.view.dialog.IFilterListener;
+import kr.co.zumo.app.lifeplus.view.dialog.LoadingDialog;
 import kr.co.zumo.app.lifeplus.view.presenter.Presenter;
 
 /**
@@ -34,6 +37,7 @@ public class SearchResultPresenter extends Presenter<SearchResultModel, ISearchR
 
   private DoubleChecker doubleCheckerSearch;
   private FilterDialog filterDialog;
+  private LoadingDialog filterWaiter;
 
   public SearchResultPresenter(SearchResultModel model, ISearchResultView view) {
     super(model, view);
@@ -75,7 +79,7 @@ public class SearchResultPresenter extends Presenter<SearchResultModel, ISearchR
 
   @Override
   protected void destroyInternal() {
-
+    hideFilterWaiter();
   }
 
   @Override
@@ -250,7 +254,17 @@ public class SearchResultPresenter extends Presenter<SearchResultModel, ISearchR
           @Override
           public void onFilterDetail(FilterDialog dialog, FilterBean filterBean) {
             // 필터 세부 항목 요청
-            model.loadFilterDetail(filterBean, new IFilterDetailListener() {
+            model.loadFilterDetail(filterBean, new IWaiterCallable() {
+              @Override
+              public void showWaiter() {
+                showFilterWaiter();
+              }
+
+              @Override
+              public void hideWaiter() {
+                hideFilterWaiter();
+              }
+            }, new IFilterDetailListener() {
               @Override
               public void onCompleted(FilterBean filterBean) {
                 dialog.setFilterDetail(filterBean);
@@ -270,4 +284,18 @@ public class SearchResultPresenter extends Presenter<SearchResultModel, ISearchR
         .show();
     }
   }
+
+  private void showFilterWaiter() {
+    if (null == filterWaiter) {
+      filterWaiter = new DialogBuilder<LoadingDialog, ICustomDialogListener>(getFragmentManager(), DialogID.LOADING)
+        .show();
+    }
+  }
+
+  private void hideFilterWaiter() {
+    if (null != filterWaiter) {
+      filterWaiter.dispose();
+      filterWaiter = null;
+    }
+  }
 }