diff options
-rw-r--r-- | .classpath | 1 | ||||
-rw-r--r-- | AndroidManifest.xml | 12 | ||||
-rw-r--r-- | lib/gson-1.7.1.jar | bin | 0 -> 173590 bytes | |||
-rw-r--r-- | res/layout/login.xml | 12 | ||||
-rw-r--r-- | res/menu/login_menu.xml | 15 | ||||
-rw-r--r-- | res/menu/main_menu.xml | 12 | ||||
-rw-r--r-- | res/values/arrays.xml | 12 | ||||
-rw-r--r-- | res/values/attrs.xml | 4 | ||||
-rw-r--r-- | res/values/strings.xml | 23 | ||||
-rw-r--r-- | res/values/style.xml | 8 | ||||
-rw-r--r-- | res/xml/preferences.xml | 24 | ||||
-rw-r--r-- | src/org/fox/ttrss/ApiRequest.java | 83 | ||||
-rw-r--r-- | src/org/fox/ttrss/LoginActivity.java | 192 | ||||
-rw-r--r-- | src/org/fox/ttrss/MainActivity.java | 74 | ||||
-rw-r--r-- | src/org/fox/ttrss/PreferencesActivity.java | 14 |
15 files changed, 481 insertions, 5 deletions
@@ -3,5 +3,6 @@ <classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="gen"/>
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
+ <classpathentry kind="lib" path="lib/gson-1.7.1.jar"/>
<classpathentry kind="output" path="bin"/>
</classpath>
diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 74d5ecfb..2496b372 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -2,17 +2,25 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="org.fox.ttrss" android:versionCode="1" - android:versionName="1.0"> + android:versionName="0.1"> <uses-sdk android:minSdkVersion="11" /> + <uses-permission android:name="android.permission.INTERNET" /> + <application android:icon="@drawable/icon" android:label="@string/app_name"> - <activity android:name=".MainActivity" + <activity android:name=".LoginActivity" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> + <activity android:name=".MainActivity" + android:label="@string/app_name"> + </activity> + <activity android:name=".PreferencesActivity" + android:label="@string/preferences"> + </activity> </application> </manifest>
\ No newline at end of file diff --git a/lib/gson-1.7.1.jar b/lib/gson-1.7.1.jar Binary files differnew file mode 100644 index 00000000..acd16c06 --- /dev/null +++ b/lib/gson-1.7.1.jar diff --git a/res/layout/login.xml b/res/layout/login.xml new file mode 100644 index 00000000..73fa1869 --- /dev/null +++ b/res/layout/login.xml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="fill_parent" + android:orientation='horizontal' + android:gravity="center" + android:layout_height="fill_parent"> + <ProgressBar android:layout_height="wrap_content" android:layout_width="wrap_content" style="?android:attr/progressBarStyleLarge" android:id="@+id/login_progress"></ProgressBar> + <TextView android:id="@+id/login_status_text" android:layout_height="wrap_content" android:layout_width="wrap_content" android:textAppearance="?android:attr/textAppearanceLarge" android:text=""></TextView> + + + +</LinearLayout> diff --git a/res/menu/login_menu.xml b/res/menu/login_menu.xml new file mode 100644 index 00000000..0c244247 --- /dev/null +++ b/res/menu/login_menu.xml @@ -0,0 +1,15 @@ + + <menu xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:id="@+id/preferences" + android:icon="@android:drawable/ic_menu_preferences" + android:title="@string/preferences" + android:showAsAction="ifRoom|withText" + /> + + <item android:id="@+id/login" + android:icon="@android:drawable/ic_menu_rotate" + android:title="@string/login_login" + android:showAsAction="ifRoom|withText" + /> + + </menu> diff --git a/res/menu/main_menu.xml b/res/menu/main_menu.xml new file mode 100644 index 00000000..8552cfcd --- /dev/null +++ b/res/menu/main_menu.xml @@ -0,0 +1,12 @@ + + <menu xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:id="@+id/preferences" + android:icon="@android:drawable/ic_menu_preferences" + android:title="@string/preferences" + android:showAsAction="ifRoom|withText"/> + + <item android:id="@+id/logout" + android:title="@string/logout" + android:showAsAction=""/> + + </menu> diff --git a/res/values/arrays.xml b/res/values/arrays.xml new file mode 100644 index 00000000..fcac426d --- /dev/null +++ b/res/values/arrays.xml @@ -0,0 +1,12 @@ + + <resources> + <string-array name="pref_theme_names"> + <item>@string/theme_dark</item> + <item>@string/theme_light</item> + </string-array> + + <string-array name="pref_theme_values"> + <item>THEME_DARK</item> + <item>THEME_LIGHT</item> + </string-array> + </resources> diff --git a/res/values/attrs.xml b/res/values/attrs.xml new file mode 100644 index 00000000..9ad509d1 --- /dev/null +++ b/res/values/attrs.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <attr name="placeholder" format="reference|color" />
+</resources>
\ No newline at end of file diff --git a/res/values/strings.xml b/res/values/strings.xml index 11c590fa..76ff7d7e 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -1,5 +1,26 @@ <?xml version="1.0" encoding="utf-8"?> <resources> - <string name="hello">Hello World, MainActivity!</string> + <string name="login_session_error">Login session refused by server</string> + <string name="login_in_progress">Logging in...</string> + <string name="login_failed">Login failed.</string> <string name="app_name">Tiny Tiny RSS</string> + <string name="login_need_configure">Please configure the application first.</string> + <string name="login_ready">Ready to login.</string> + <string name="login_login">Log in</string> + <string name="logout">Log out</string> + <string name="login">Login</string> + <string name="password">Password</string> + <string name="default_url">http://example.domain/tt-rss/</string> + <string name="authentication">Authentication</string> + <string name="look_and_feel">Look and feel</string> + <string name="pref_theme">Theme</string> + <string name="pref_theme_long">Changes color theme of the application.</string> + <string name="ttrss_url">Tiny Tiny RSS URL</string> + <string name="auto_login">Login automatically</string> + <string name="theme_dark">Dark</string> + <string name="preferences">Preferences</string> + <string name="theme_light">Light</string> + <string name="login_api_disabled">Login failed: API disabled.</string> + <string name="login_wrong_password">Login failed: username or password incorrect.</string> + <string name="login_success">Logged in.</string> </resources> diff --git a/res/values/style.xml b/res/values/style.xml new file mode 100644 index 00000000..952f70ff --- /dev/null +++ b/res/values/style.xml @@ -0,0 +1,8 @@ +<resources>
+ <style name="LightTheme" parent="android:Theme.Holo.Light">
+ </style>
+
+ <style name="DarkTheme" parent="android:Theme.Holo">
+ </style>
+
+</resources>
\ No newline at end of file diff --git a/res/xml/preferences.xml b/res/xml/preferences.xml new file mode 100644 index 00000000..c158a5f8 --- /dev/null +++ b/res/xml/preferences.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8"?>
+
+<PreferenceScreen
+ xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <PreferenceCategory android:title="@string/authentication">
+ + <EditTextPreference android:title="@string/login" android:key="login" android:singleLine="true"></EditTextPreference>
+ <EditTextPreference android:title="@string/password" android:key="password" android:singleLine="true" android:password="true"></EditTextPreference>
+ <EditTextPreference android:key="ttrss_url" android:title="@string/ttrss_url" android:singleLine="true" textUri="true" android:hint="@string/default_url"></EditTextPreference>
+ <CheckBoxPreference android:defaultValue="true" android:title="@string/auto_login" android:key="auto_login" />
+
+ </PreferenceCategory>
+
+ <PreferenceCategory android:title="@string/look_and_feel">
+ <ListPreference
+ android:title="@string/pref_theme"
+ android:key="theme"
+ android:defaultValue="THEME_DARK"
+ android:entries="@array/pref_theme_names"
+ android:entryValues="@array/pref_theme_values" android:summary="@string/pref_theme_long"/>
+ </PreferenceCategory>
+
+</PreferenceScreen>
\ No newline at end of file diff --git a/src/org/fox/ttrss/ApiRequest.java b/src/org/fox/ttrss/ApiRequest.java new file mode 100644 index 00000000..aaac25c2 --- /dev/null +++ b/src/org/fox/ttrss/ApiRequest.java @@ -0,0 +1,83 @@ +package org.fox.ttrss;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.UnsupportedEncodingException;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+
+import org.apache.http.HttpResponse;
+import org.apache.http.client.ClientProtocolException;
+import org.apache.http.client.entity.UrlEncodedFormEntity;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.DefaultHttpClient;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonParser;
+
+import android.content.SharedPreferences;
+import android.os.AsyncTask;
+import android.preference.PreferenceManager;
+import android.util.Log;
+
+public class ApiRequest extends AsyncTask<HashMap<String,String>, Integer, JsonElement> {
+ private final String TAG = this.getClass().getSimpleName();
+
+ protected String m_sessionId;
+ protected String m_apiEndpoint;
+
+ protected ApiRequest(String sessionId, String apiEndpoint) {
+ super();
+ m_sessionId = sessionId;
+ m_apiEndpoint = apiEndpoint;
+ }
+
+ @Override
+ protected JsonElement doInBackground(HashMap<String,String>... params) {
+
+ Gson gson = new Gson();
+
+ String requestStr = gson.toJson(params);
+
+ // FIXME ugly hack
+ requestStr = requestStr.substring(1).substring(0, requestStr.length()-2);
+
+ Log.d(TAG, "executing API request...: " + requestStr + " " + m_apiEndpoint);
+
+ DefaultHttpClient client = new DefaultHttpClient();
+ HttpPost httpPost = new HttpPost(m_apiEndpoint + "/api/");
+
+ try {
+ httpPost.setEntity(new StringEntity(requestStr, "utf-8"));
+ HttpResponse execute = client.execute(httpPost);
+
+ InputStream content = execute.getEntity().getContent();
+
+ BufferedReader buffer = new BufferedReader(
+ new InputStreamReader(content));
+
+ String s = "";
+ String response = "";
+
+ while ((s = buffer.readLine()) != null) {
+ response += s;
+ }
+
+ Log.d(TAG, "Server returned: " + response);
+
+ JsonParser parser = new JsonParser();
+
+ return parser.parse(response);
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ return null;
+ }
+}
diff --git a/src/org/fox/ttrss/LoginActivity.java b/src/org/fox/ttrss/LoginActivity.java new file mode 100644 index 00000000..6cf1ff1e --- /dev/null +++ b/src/org/fox/ttrss/LoginActivity.java @@ -0,0 +1,192 @@ +package org.fox.ttrss; + +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; + +import org.apache.http.HttpResponse; +import org.apache.http.NameValuePair; +import org.apache.http.client.entity.UrlEncodedFormEntity; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.impl.client.DefaultHttpClient; +import org.apache.http.message.BasicNameValuePair; +import org.json.JSONObject; +import org.json.JSONTokener; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; + +import android.app.Activity; +import android.content.ComponentName; +import android.content.Intent; +import android.content.ServiceConnection; +import android.content.SharedPreferences; +import android.os.AsyncTask; +import android.os.Bundle; +import android.os.IBinder; +import android.preference.PreferenceManager; +import android.util.Log; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.widget.TextView; +import android.widget.Toast; + +public class LoginActivity extends Activity { + private final String TAG = this.getClass().getSimpleName(); + private SharedPreferences m_prefs; + private String m_themeName = ""; + private String m_sessionId = null; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + m_prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); + + if (m_prefs.getString("theme", "THEME_DARK").equals("THEME_DARK")) { + setTheme(R.style.DarkTheme); + } else { + setTheme(R.style.LightTheme); + } + + m_themeName = m_prefs.getString("theme", "THEME_DARK"); + + setContentView(R.layout.login); + } + + protected void updateLoginStatus(int id) { + TextView tv = (TextView) findViewById(R.id.login_status_text); + if (tv != null) { + tv.setText(id); + } + } + + protected void showLoginProgress(boolean show) { + View v = findViewById(R.id.login_progress); + v.setVisibility((show) ? View.VISIBLE : View.GONE); + } + + @Override + public void onResume() { + super.onResume(); + + if (!m_prefs.getString("theme", "THEME_DARK").equals(m_themeName)) { + Intent refresh = new Intent(this, LoginActivity.class); + startActivity(refresh); + finish(); + } + + showLoginProgress(false); + + if (isConfigured()) { + updateLoginStatus(R.string.login_ready); + } else { + updateLoginStatus(R.string.login_need_configure); + } + + } + + public boolean isConfigured() { + String login = m_prefs.getString("login", ""); + String password = m_prefs.getString("password", ""); + String ttrssUrl = m_prefs.getString("ttrss_url", ""); + + return !(login.equals("") || password.equals("") || ttrssUrl.equals("")); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + MenuInflater inflater = getMenuInflater(); + inflater.inflate(R.menu.login_menu, menu); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case R.id.preferences: + Intent intent = new Intent(this, PreferencesActivity.class); + startActivityForResult(intent, 0); + return true; + case R.id.login: + performLogin(); + return true; + default: + return super.onOptionsItemSelected(item); + } + } + + @SuppressWarnings({ "serial", "unchecked" }) + private void performLogin() { + ApiRequest task = new ApiRequest(null, m_prefs.getString("ttrss_url", null)) { + @Override + protected void onPostExecute(JsonElement result) { + if (result != null) { + try { + + JsonObject rv = result.getAsJsonObject(); + + int status = rv.get("status").getAsInt(); + + if (status == 0) { + JsonObject content = rv.get("content").getAsJsonObject(); + if (content != null) { + m_sessionId = content.get("session_id").getAsString(); + + showLoginProgress(false); + updateLoginStatus(R.string.login_success); + + Intent intent = new Intent(getApplicationContext(), MainActivity.class); + intent.putExtra("sessionId", m_sessionId); + startActivityForResult(intent, 0); + + finish(); + return; + } + } else { + JsonObject content = rv.get("content").getAsJsonObject(); + + if (content != null) { + String error = content.get("error").getAsString(); + + if (error.equals("LOGIN_ERROR")) { + updateLoginStatus(R.string.login_wrong_password); + } else if (error.equals("API_DISABLED")) { + updateLoginStatus(R.string.login_api_disabled); + } + } + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + showLoginProgress(false); + updateLoginStatus(R.string.login_failed); + + } + }; + + updateLoginStatus(R.string.login_in_progress); + showLoginProgress(true); + + task.execute(new HashMap<String,String>() { + { + put("op", "login"); + put("user", m_prefs.getString("login", null)); + put("password", m_prefs.getString("password", null)); + } + }); + + } + + @Override + protected void onDestroy() { + super.onDestroy(); + } +}
\ No newline at end of file diff --git a/src/org/fox/ttrss/MainActivity.java b/src/org/fox/ttrss/MainActivity.java index 5ee2fc62..a25e4e8f 100644 --- a/src/org/fox/ttrss/MainActivity.java +++ b/src/org/fox/ttrss/MainActivity.java @@ -1,16 +1,86 @@ package org.fox.ttrss; import android.app.Activity; +import android.content.Intent; +import android.content.SharedPreferences; import android.os.Bundle; +import android.preference.PreferenceManager; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; public class MainActivity extends Activity { + private SharedPreferences m_prefs; + private String m_themeName = ""; + private String m_sessionId; + /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setTheme(android.R.style.Theme_Holo_Light); + m_prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); + + if (m_prefs.getString("theme", "THEME_DARK").equals("THEME_DARK")) { + setTheme(R.style.DarkTheme); + } else { + setTheme(R.style.LightTheme); + } + + m_themeName = m_prefs.getString("theme", "THEME_DARK"); - setContentView(R.layout.main); + Bundle extras = getIntent().getExtras(); + + if (extras != null) { + m_sessionId = extras.getString("sessionId"); + } else if (savedInstanceState != null) { + m_sessionId = savedInstanceState.getString("sessionId"); + } + + setContentView(R.layout.main); } + + @Override + public void onSaveInstanceState (Bundle out) { + super.onSaveInstanceState(out); + + out.putString("sessionId", m_sessionId); + } + + @Override + public void onResume() { + super.onResume(); + + if (!m_prefs.getString("theme", "THEME_DARK").equals(m_themeName)) { + Intent refresh = new Intent(this, LoginActivity.class); + startActivity(refresh); + finish(); + } + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + MenuInflater inflater = getMenuInflater(); + inflater.inflate(R.menu.main_menu, menu); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case R.id.preferences: + Intent intent = new Intent(this, PreferencesActivity.class); + startActivityForResult(intent, 0); + return true; + case R.id.logout: + intent = new Intent(this, LoginActivity.class); + intent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION); + startActivityForResult(intent, 0); + finish(); + return true; + default: + return super.onOptionsItemSelected(item); + } + } + }
\ No newline at end of file diff --git a/src/org/fox/ttrss/PreferencesActivity.java b/src/org/fox/ttrss/PreferencesActivity.java new file mode 100644 index 00000000..5d538fc0 --- /dev/null +++ b/src/org/fox/ttrss/PreferencesActivity.java @@ -0,0 +1,14 @@ +package org.fox.ttrss;
+
+import android.os.Bundle;
+import android.preference.PreferenceActivity;
+
+public class PreferencesActivity extends PreferenceActivity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ addPreferencesFromResource(R.xml.preferences);
+ }
+}
|