Setting + search + bug fixing

This commit is contained in:
Vladislav Khorev 2014-11-20 10:57:28 +00:00
parent 75dd42a703
commit 3258788e16
19 changed files with 664 additions and 65 deletions

View File

@ -23,31 +23,10 @@
android:screenOrientation="portrait" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data android:name="android.app.searchable"
android:resource="@xml/searchable" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!--
<activity
android:name=".SearchResultActivity"
android:label="@string/app_name"
android:configChanges="orientation"
android:screenOrientation="portrait" >
<intent-filter>
<action android:name="android.intent.action.SEARCH" />
</intent-filter>
<meta-data android:name="android.app.searchable"
android:resource="@xml/searchable" />
</activity>
-->
</application>
</manifest>

View File

@ -0,0 +1,18 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="fishrungames.bashgid.SearchFragment" >
<ListView
android:id="@+id/listView"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
</ListView>
</LinearLayout>

View File

@ -0,0 +1,65 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="fishrungames.bashgid.SettingsFragment" >
<TextView
android:id="@+id/selectLanguageTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/select_language"
android:textSize="26sp" />
<LinearLayout
android:id="@+id/flag_view"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<ImageButton
android:id="@+id/image_flag_usa"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:layout_weight="1"
android:adjustViewBounds="true"
android:background="@drawable/transparent"
android:contentDescription="@string/lang_english"
android:scaleType="fitCenter"
android:src="@drawable/united_states_icon_button"
android:onClick="OnSelectEnglish" />
<ImageButton
android:id="@+id/image_flag_russia"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:layout_weight="1"
android:adjustViewBounds="true"
android:background="@drawable/transparent"
android:contentDescription="@string/lang_russian"
android:scaleType="fitCenter"
android:src="@drawable/russia_icon_button"
android:onClick="OnSelectRussian" />
<ImageButton
android:id="@+id/image_flag_china"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:layout_weight="1"
android:adjustViewBounds="true"
android:background="@drawable/transparent"
android:contentDescription="@string/lang_chinese"
android:scaleType="fitCenter"
android:src="@drawable/china_icon_button"
android:onClick="OnSelectChinese" />
</LinearLayout>
</LinearLayout>

View File

@ -0,0 +1,44 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="4dp"
android:background="@color/bkg1"
android:orientation="horizontal"
android:paddingBottom="4dp"
android:paddingTop="4dp"
android:showDividers="middle" >
<ImageButton
android:id="@+id/imageButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_margin="6dp"
android:background="@drawable/transparent"
android:src="@drawable/transparent_button"
android:contentDescription="@string/news_content_description" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical" >
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/transparent_button"
android:gravity="left|center_vertical"
android:minHeight="0dip"
android:minWidth="0dip"
android:textColor="@color/text_grey" />
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
</LinearLayout>

View File

@ -0,0 +1,22 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/bkg1"
android:orientation="vertical"
android:paddingLeft="20dp"
android:paddingRight="20dp"
tools:context="fishrungames.bashgid.SearchFragment" >
<EditText
android:id="@+id/editText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:hint="@string/enter_search_query"
android:inputType="text" >
<requestFocus />
</EditText>
</LinearLayout>

View File

@ -10,8 +10,11 @@
<string name="select_language">Выберите язык:</string>
<string name="search_title">Поиск</string>
<string name="enter_search_query">Введите запрос</string>
<string name="news_record_not_available">Запись недоступна</string>
<string name="other_news">Другие новости…</string>

View File

@ -10,6 +10,8 @@
<string name="search_title">搜索标题</string>
<string name="enter_search_query">输入问题</string>
<string name="news_record_not_available">无法查看新闻记录</string>
<string name="other_news">其他新闻…</string>

View File

@ -16,7 +16,7 @@
<string name="search_title">Search</string>
<string name="search_hint">Search hint</string>
<string name="enter_search_query">Enter search query</string>
<string name="news_record_not_available">Record is not available</string>

View File

@ -6,10 +6,8 @@ import java.util.Locale;
import fishrungames.bashgid.core.NewsManager.NewsRecord;
import fishrungames.bashgid.core.db.NewsDataSource;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.widget.SearchView;
import android.support.v4.app.Fragment;
import android.app.SearchManager;
import android.content.Context;
import android.content.res.Configuration;
import android.os.Bundle;
@ -25,7 +23,13 @@ public class MainActivity extends ActionBarActivity implements NavigationDrawerF
public static final String TAG_FROM_MAINFRAGMENT_TO_NEWSRECORDFRAGMENT = "TAG_FROM_MAINFRAGMENT_TO_NEWSRECORDFRAGMENT";
public static final String TAG_FROM_NEWSLISTFRAGMENT_TO_NEWSRECORDFRAGMENT = "TAG_FROM_NEWSLISTFRAGMENT_TO_NEWSRECORDFRAGMENT";
public static final String TAG_FROM_SEARCHFRAGMENT_TO_NEWSRECORDFRAGMENT = "TAG_FROM_SEARCHFRAGMENT_TO_NEWSRECORDFRAGMENT";
public static final String TAG_TO_SEARCHFRAGMENT = "SearchFragment";
static MainActivity instance = null;
private NavigationDrawerFragment mNavigationDrawerFragment = null;
@ -49,7 +53,7 @@ public class MainActivity extends ActionBarActivity implements NavigationDrawerF
newsDataSource = new NewsDataSource(this);
newsDataSource.open();
}
public static MainActivity getInstance()
@ -129,6 +133,20 @@ public class MainActivity extends ActionBarActivity implements NavigationDrawerF
mNavigationDrawerFragment.EnableDrawer();
}
public void OpenSearchScreen()
{
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new SearchFragment(), TAG_TO_SEARCHFRAGMENT).commit();
mNavigationDrawerFragment.EnableDrawer();
}
public void OpenSearchScreen(boolean restorePreviousSearch)
{
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new SearchFragment(restorePreviousSearch), TAG_TO_SEARCHFRAGMENT).commit();
mNavigationDrawerFragment.EnableDrawer();
}
public void OpenNewsRecordScreen(NewsRecord newsRecord, String tag)
{
// Xperimental -- addToBackStack provoke error "Class not found". Need
@ -170,18 +188,7 @@ public class MainActivity extends ActionBarActivity implements NavigationDrawerF
{
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.global, menu);
/*
SearchManager searchManager =
(SearchManager) getSystemService(Context.SEARCH_SERVICE);
SearchView searchView =
(SearchView) menu.findItem(R.id.action_search).getActionView();
searchView.setSearchableInfo(
searchManager.getSearchableInfo(getComponentName()));
*/
inflater.inflate(R.menu.global, menu);
return super.onCreateOptionsMenu(menu);
}
@ -192,6 +199,16 @@ public class MainActivity extends ActionBarActivity implements NavigationDrawerF
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_search)
{
if (getSupportFragmentManager().findFragmentByTag(TAG_TO_SEARCHFRAGMENT) == null)
{
OpenSearchScreen();
}
return true;
}
if (id == R.id.action_settings)
{
return true;
@ -233,6 +250,20 @@ public class MainActivity extends ActionBarActivity implements NavigationDrawerF
return;
}
if (getSupportFragmentManager().findFragmentByTag(TAG_FROM_SEARCHFRAGMENT_TO_NEWSRECORDFRAGMENT) != null)
{
OpenSearchScreen(true);
return;
}
if (getSupportFragmentManager().findFragmentByTag(TAG_TO_SEARCHFRAGMENT) != null)
{
OpenMainScreen();
return;
}
super.onBackPressed();

View File

@ -5,7 +5,8 @@ import java.util.ArrayList;
import fishrungames.bashgid.core.ImageManager;
import fishrungames.bashgid.core.NewsManager;
import fishrungames.bashgid.core.NewsManager.NewsRecord;
import fishrungames.bashgid.core.NewsManager.NewsUpdatedCallbackInterface;
import fishrungames.bashgid.core.NewsUpdatedCallbackInterface;
import fishrungames.bashgid.core.RemoveCallbackInterface;
import android.content.Context;
import android.os.Bundle;
import android.support.v4.app.Fragment;
@ -47,7 +48,7 @@ public class MainPageFragment extends Fragment implements NewsUpdatedCallbackInt
ListView listView;
View header;
NewsManager.RemoveCallbackInterface downloadNewsCanceller = null;
RemoveCallbackInterface downloadNewsCanceller = null;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

View File

@ -259,8 +259,6 @@ public class NavigationDrawerFragment extends Fragment {
// If the drawer is open, show the global app actions in the action bar. See also
// showGlobalContextActionBar, which controls the top-left area of the action bar.
//inflater.inflate(R.menu.global, menu);
showGlobalContextActionBar();
super.onCreateOptionsMenu(menu, inflater);

View File

@ -6,7 +6,8 @@ import java.util.ArrayList;
import fishrungames.bashgid.core.ImageManager;
import fishrungames.bashgid.core.NewsManager;
import fishrungames.bashgid.core.NewsManager.NewsRecord;
import fishrungames.bashgid.core.NewsManager.NewsUpdatedCallbackInterface;
import fishrungames.bashgid.core.NewsUpdatedCallbackInterface;
import fishrungames.bashgid.core.RemoveCallbackInterface;
import fishrungames.bashgid.core.db.NewsDataSource;
import android.content.Context;
import android.os.Bundle;
@ -31,7 +32,7 @@ public class NewsListFragment extends Fragment implements NewsUpdatedCallbackInt
ArrayList<NewsRecord> newsRecordArr;
NewsManager.RemoveCallbackInterface downloadNewsCanceller = null;
RemoveCallbackInterface downloadNewsCanceller = null;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

View File

@ -0,0 +1,224 @@
package fishrungames.bashgid;
import java.util.ArrayList;
import fishrungames.bashgid.core.NewsManager;
import fishrungames.bashgid.core.NewsManager.NewsRecord;
import fishrungames.bashgid.core.db.NewsDataSource;
import fishrungames.bashgid.core.ImageManager;
import fishrungames.bashgid.core.NewsSearchRunnable;
import fishrungames.bashgid.core.NewsUpdatedCallbackInterface;
import android.content.Context;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ListView;
import android.widget.TextView;
public class SearchFragment extends Fragment implements NewsUpdatedCallbackInterface
{
ListView listView;
ListAdapter listAdapter;
EditText searchEditText;
ArrayList<NewsRecord> searchResultArr = new ArrayList<NewsRecord>();
volatile boolean searchIsPerformingNow = false;
NewsSearchRunnable nextSearchRunnable = null;
boolean restorePreviousSearch = false;
public SearchFragment()
{
}
public SearchFragment(boolean restorePreviousSearch)
{
this.restorePreviousSearch = restorePreviousSearch;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_search_page, container, false);
listView = (ListView) rootView.findViewById(R.id.listView);
listAdapter = new ListAdapter(getActivity());
listView.setAdapter(listAdapter);
View header = inflater.inflate(R.layout.search_page_list_header, null);
searchEditText = (EditText) header.findViewById(R.id.editText);
if (restorePreviousSearch)
{
searchEditText.setText(NewsManager.GetInstance().getLastSearchQuery());
searchResultArr = NewsManager.GetInstance().getSearchResultNews();
}
searchEditText.addTextChangedListener(new TextWatcher(){
public void afterTextChanged(Editable s) {
String text = searchEditText.getText().toString();
CallUpdateNews(text);
}
public void beforeTextChanged(CharSequence s, int start, int count, int after){}
public void onTextChanged(CharSequence s, int start, int before, int count){}
});
listView.addHeaderView(header);
return rootView;
}
public class ListAdapter extends BaseAdapter {
private Context mContext;
public ListAdapter(Context c) {
mContext = c;
}
public int getCount() {
return searchResultArr.size();
}
public Object getItem(int position) {
return null;
}
public long getItemId(int position) {
return 0;
}
// create a new ImageView for each item referenced by the Adapter
public View getView(int position, View convertView, ViewGroup parent) {
View view;
if (convertView == null) { // if it's not recycled, initialize some attributes
LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(R.layout.search_page_list_element, null);
} else {
view = convertView;
}
ImageButton imageButton = (ImageButton) view.findViewById(R.id.imageButton);
Button button = (Button) view.findViewById(R.id.button);
TextView textView = (TextView) view.findViewById(R.id.textView);
ImageManager.getInstance().ApplyImageToImageView(imageButton, searchResultArr.get(position).imageId);
button.setText(searchResultArr.get(position).title);
textView.setText(NewsDataSource.iso8601Format.format(searchResultArr.get(position).pubDate));
button.setOnClickListener(new ButtonOnClickListener(searchResultArr.get(position)));
imageButton.setOnClickListener(new ButtonOnClickListener(searchResultArr.get(position)));
return view;
}
}
@Override
public void OnNewsUpdated()
{
getActivity().runOnUiThread(new RefreshSearchListRunnable());
}
public void CallUpdateNews(String text)
{
if (!searchIsPerformingNow)
{
searchIsPerformingNow = true;
NewsSearchRunnable runnable = new NewsSearchRunnable(this, text);
ImmediateSearchNews(runnable);
}
else
{
nextSearchRunnable = new NewsSearchRunnable(this, text);
}
}
private void ImmediateSearchNews(NewsSearchRunnable runnable)
{
Thread thread = new Thread(runnable);
thread.start();
}
private class RefreshSearchListRunnable implements Runnable
{
@Override
public void run()
{
searchResultArr = NewsManager.GetInstance().getSearchResultNews();
listAdapter.notifyDataSetChanged();
searchIsPerformingNow = false;
if (nextSearchRunnable != null)
{
ImmediateSearchNews(nextSearchRunnable);
nextSearchRunnable = null;
}
}
}
public static class ButtonOnClickListener implements OnClickListener
{
NewsRecord newsRecord;
public ButtonOnClickListener(NewsRecord newsRecord)
{
this.newsRecord = newsRecord;
}
@Override
public void onClick(View v)
{
MainActivity.getInstance().OpenNewsRecordScreen(newsRecord, MainActivity.TAG_FROM_SEARCHFRAGMENT_TO_NEWSRECORDFRAGMENT);
}
}
}

View File

@ -10,7 +10,7 @@ import android.util.Log;
import fishrungames.bashgid.MainActivity;
import fishrungames.bashgid.core.db.BashgidSqliteHelper;
public class NewsManager {
@ -30,6 +30,10 @@ public class NewsManager {
private ArrayList<NewsRecord> newsRecord = new ArrayList<NewsRecord>();
private volatile Semaphore newsSearchResultMutex = new Semaphore(1, true);
private ArrayList<NewsRecord> newsSearchResult = new ArrayList<NewsRecord>();
String LastSearchQuery = "";
public static boolean CanCallSynchronization()
{
@ -220,18 +224,7 @@ public class NewsManager {
}
}
public static interface NewsUpdatedCallbackInterface
{
public void OnNewsUpdated();
}
public static interface RemoveCallbackInterface
{
public void RemoveCallback();
}
public NewsManager()
{
try
@ -276,6 +269,62 @@ public class NewsManager {
return result;
}
public ArrayList<NewsRecord> getSearchResultNews()
{
ArrayList<NewsRecord> result = new ArrayList<NewsRecord>();
try
{
newsSearchResultMutex.acquire();
try
{
result.addAll(newsSearchResult);
} finally
{
newsSearchResultMutex.release();
}
} catch (InterruptedException ie)
{
Log.e("Error in getSearchResultNews", "Error in getSearchResultNews");
}
return result;
}
public String getLastSearchQuery()
{
//Should always be called from main thread
return LastSearchQuery;
}
public void searchNews(String searchText)
{
ArrayList<NewsRecord> result = new ArrayList<NewsRecord>();
result = MainActivity.getInstance().newsDataSource.searchNewsByString(searchText);
try
{
newsSearchResultMutex.acquire();
try
{
LastSearchQuery = searchText;
newsSearchResult = result;
} finally
{
newsSearchResultMutex.release();
}
} catch (InterruptedException ie)
{
Log.e("Error in getSearchResultNews", "Error in getSearchResultNews");
}
}
public static ArrayList<String> ExtractEnclosureImageUrl(ArrayList<RssReader.Rss2Item> rss2ItemArr)
{

View File

@ -0,0 +1,12 @@
package fishrungames.bashgid.core;
import java.util.ArrayList;
import fishrungames.bashgid.core.NewsManager.NewsRecord;
public interface NewsSearchResultInterface
{
public void OnNewsUpdated(ArrayList<NewsRecord> newsRecordArr);
}

View File

@ -0,0 +1,92 @@
package fishrungames.bashgid.core;
import java.util.concurrent.Semaphore;
import android.util.Log;
public class NewsSearchRunnable implements Runnable, RemoveCallbackInterface
{
private volatile Semaphore callbackMutex = new Semaphore(1, true);
private NewsUpdatedCallbackInterface callback = null;
private String query;
public NewsSearchRunnable(NewsUpdatedCallbackInterface callback, String query)
{
this.query = query;
try
{
callbackMutex.acquire();
try
{
this.callback = callback;
} finally
{
callbackMutex.release();
}
} catch (InterruptedException ie)
{
Log.e("Error in NewsSearchRunnable", "Error in NewsSearchRunnable");
}
}
@Override
public void run()
{
NewsManager.GetInstance().searchNews(query);
//After all
try
{
callbackMutex.acquire();
try
{
if (callback != null)
{
callback.OnNewsUpdated();
callback = null;
}
} finally
{
callbackMutex.release();
}
} catch (InterruptedException ie)
{
Log.e("Error in DownloadNewsRunnable", "Error in DownloadNewsRunnable");
}
}
@Override
public void RemoveCallback()
{
try
{
callbackMutex.acquire();
try
{
callback = null;
} finally
{
callbackMutex.release();
}
} catch (InterruptedException ie)
{
Log.e("Error in NewsSearchRunnable", "Error in NewsSearchRunnable");
}
}
}

View File

@ -0,0 +1,8 @@
package fishrungames.bashgid.core;
public interface NewsUpdatedCallbackInterface
{
//Xperimental -- maybe allow it to return value? Array of news
public void OnNewsUpdated();
}

View File

@ -0,0 +1,8 @@
package fishrungames.bashgid.core;
public interface RemoveCallbackInterface
{
public void RemoveCallback();
}

View File

@ -167,13 +167,13 @@ public class NewsDataSource
{
ArrayList<NewsManager.NewsRecord> newsRecordArr = new ArrayList<NewsManager.NewsRecord>();
/*
try
{
mutex.acquire();
try
{
*/
if (database != null)
{
Cursor cursor = database.query(BashgidSqliteHelper.TABLE_NEWS, allColumns, null, null, null, null, null);
@ -190,16 +190,58 @@ public class NewsDataSource
cursor.close();
}
/*
} finally
{
mutex.release();
}
} catch (InterruptedException ie)
{
Log.e("Error when calling replaceNews", "Error when calling replaceNews");
Log.e("Error when calling getNews", "Error when calling getNews");
}
*/
return newsRecordArr;
}
public ArrayList<NewsManager.NewsRecord> searchNewsByString(String searchText)
{
ArrayList<NewsManager.NewsRecord> newsRecordArr = new ArrayList<NewsManager.NewsRecord>();
try
{
mutex.acquire();
try
{
if (database != null)
{
Cursor cursor = database.query(true, BashgidSqliteHelper.TABLE_NEWS, allColumns, BashgidSqliteHelper.COLUMN_TITLE + " LIKE '%"+searchText+"%'", null, null, null, null, null);
cursor.moveToFirst();
while (!cursor.isAfterLast())
{
NewsManager.NewsRecord newsRecord = cursorToNewsRecord(cursor);
newsRecordArr.add(newsRecord);
cursor.moveToNext();
}
cursor.close();
}
} finally
{
mutex.release();
}
} catch (InterruptedException ie)
{
Log.e("Error when calling searchNewsByString", "Error when calling searchNewsByString");
}
return newsRecordArr;
}