Added user's profile download to the intial logging in process. Added stub for profile display screen. Added stub menu item for refresh. Modified preference handling to use a util class.

This commit is contained in:
RyanBateman 2012-07-04 17:24:42 -04:00
parent 99637a2314
commit 386e18da71
28 changed files with 366 additions and 39 deletions

View file

@ -25,9 +25,14 @@
<action android:name="android.intent.action.MAIN" />
</intent-filter>
</activity>
<activity
android:name=".activity.Main"
android:label="@string/newsblur" />
<activity
android:name=".activity.Profile"
android:label="@string/profile" />
<service android:name=".service.SyncService" />

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

View file

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<View
android:layout_width="fill_parent"
android:layout_height="8dip"
android:layout_alignParentTop="true"
android:background="@drawable/orangeline_shadow" />
<FrameLayout
android:id="@+id/profile_details"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</RelativeLayout>

View file

@ -37,7 +37,7 @@
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_marginBottom="40dp"
android:layout_marginBottom="20dp"
android:layout_marginTop="60dp"
android:contentDescription="@string/description_signup_button"
android:text="@string/login_button_signup" />
@ -48,7 +48,7 @@
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_marginBottom="40dp"
android:layout_marginBottom="20dp"
android:layout_marginTop="60dp"
android:contentDescription="@string/description_login_button"
android:text="@string/login_button_login" />

View file

@ -0,0 +1,55 @@
<?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:orientation="horizontal"
android:background="@color/white">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:padding="20dp">
<ImageView
android:id="@+id/profile_picture"
android:layout_width="50dp"
android:layout_height="50dp"
android:contentDescription="@string/description_profile_picture"
android:src="@drawable/person"
android:background="@color/darkgray"
android:padding="10dp"
android:scaleType="fitCenter" />
</LinearLayout>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<TextView
android:text="USER PROFILE NAME"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:textSize="20dp"
android:layout_weight="1"
android:paddingTop="5dp"
android:paddingBottom="5dp"
android:textColor="@color/lightorange"
android:textStyle="bold"/>
<TextView
android:text="bio"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:textSize="12dp"
android:layout_weight="1"
android:paddingTop="5dp"
android:paddingBottom="5dp"
android:textStyle="italic"
android:textColor="@color/lightgray" />
</LinearLayout>
</LinearLayout>

View file

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:id="@+id/menu_refresh"
android:icon="@drawable/refresh"
android:title="@string/menu_refresh"
android:showAsAction="always" />
<item android:id="@+id/menu_profile"
android:icon="@drawable/person"
android:title="@string/menu_profile"
android:showAsAction="ifRoom" />
</menu>

View file

@ -20,10 +20,11 @@
<string name="description_login_logo">NewsBlur Logo</string>
<string name="description_signup_button">Press to sign up</string>
<string name="description_favicon">The feed\'s favicon</string>
<string name="description_profile_picture">The user\'s profile picture</string>
<string name="menu_profile">Profile</string>
<string name="menu_refresh">Refresh</string>
<string name="profile">Profile</string>
</resources>

View file

@ -10,7 +10,7 @@
<item name="android:textColor">@color/white</item>
<item name="android:textColorHint">@color/hintgray</item>
</style>
<style name="button" parent="@android:style/Widget.Button">
<item name="android:background">@drawable/selector_button_background</item>
<item name="android:textColor">@color/white</item>
@ -22,5 +22,10 @@
<item name="android:textSize">20dp</item>
<item name="android:padding">10dp</item>
</style>
<style name="actionbar" parent="Widget.Sherlock.ActionBar">
<item name="android:background">@drawable/actionbar_background</item>
<item name="background">@drawable/actionbar_background</item>
</style>
</resources>

View file

@ -3,5 +3,7 @@
<style name="NewsBlurTheme" parent="@style/Theme.Sherlock" >
<item name="android:editTextStyle">@style/edittext</item>
<item name="android:buttonStyle">@style/button</item>
<item name="actionBarStyle">@style/actionbar</item>
<item name="android:actionBarStyle">@style/actionbar</item>
</style>
</resources>

View file

@ -22,9 +22,9 @@ public class Login extends FragmentActivity implements LoginFragment.LoginFragme
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// preferenceCheck();
preferenceCheck();
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.login);
setContentView(R.layout.activity_login);
fragmentManager = getSupportFragmentManager();
if (fragmentManager.findFragmentByTag(currentTag) == null) {
@ -54,8 +54,8 @@ public class Login extends FragmentActivity implements LoginFragment.LoginFragme
}
private void preferenceCheck() {
final SharedPreferences preferences = getSharedPreferences(APIConstants.PREFERENCES, 0);
if (preferences.getString(APIConstants.PREF_COOKIE, null) != null) {
final SharedPreferences preferences = getSharedPreferences(PrefConstants.PREFERENCES, 0);
if (preferences.getString(PrefConstants.PREF_COOKIE, null) != null) {
final Intent mainIntent = new Intent(this, Main.class);
startActivity(mainIntent);
}

View file

@ -1,10 +1,13 @@
package com.newsblur.activity;
import android.content.Intent;
import android.os.Bundle;
import com.actionbarsherlock.app.ActionBar;
import com.actionbarsherlock.app.SherlockFragmentActivity;
import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuInflater;
import com.actionbarsherlock.view.MenuItem;
import com.newsblur.R;
public class Main extends SherlockFragmentActivity {
@ -14,22 +17,32 @@ public class Main extends SherlockFragmentActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
setContentView(R.layout.activity_main);
setupActionBar();
}
private void setupActionBar() {
actionBar = getSupportActionBar();
actionBar.setBackgroundDrawable(getResources().getDrawable(R.drawable.actionbar_background));
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
return true;
MenuInflater inflater = getSupportMenuInflater();
inflater.inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_profile:
Intent profileIntent = new Intent(this, Profile.class);
startActivity(profileIntent);
return true;
}
return super.onOptionsItemSelected(item);
}
}

View file

@ -0,0 +1,25 @@
package com.newsblur.activity;
public class PrefConstants {
public static final String PREFERENCES = "preferences";
public static final String PREF_COOKIE = "login_cookie";
public final static String USER_USERNAME = "username";
public final static String USER_WEBSITE = "website";
public final static String USER_BIO = "bio";
public final static String USER_FEED_ADDRESS = "feed_address";
public final static String USER_FEED_TITLE = "feed_link";
public final static String USER_FOLLOWER_COUNT = "follower_count";
public final static String USER_LOCATION = "location";
public final static String USER_ID = "id";
public final static String USER_PHOTO_SERVICE = "photo_service";
public final static String USER_PHOTO_URL = "photo_url";
public final static String USER_POPULAR_PUBLISHERS = "popular_publishers";
public final static String USER_STORIES_LAST_MONTH = "stories_last_month";
public final static String USER_AVERAGE_STORIES_PER_MONTH = "average_stories_per_month";
public final static String USER_FOLLOWING_COUNT = "following_count";
public final static String USER_SUBSCRIBER_COUNT = "subscribers_count";
public final static String USER_SHARED_STORIES_COUNT = "shared_stories_count";
}

View file

@ -0,0 +1,35 @@
package com.newsblur.activity;
import android.os.Bundle;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.util.Log;
import com.actionbarsherlock.app.SherlockFragmentActivity;
import com.newsblur.R;
import com.newsblur.fragment.ProfileDetailsFragment;
public class Profile extends SherlockFragmentActivity {
private FragmentManager fragmentManager;
private String detailsFragment = "details";
private String TAG = "ProfileActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_profile);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
fragmentManager = getSupportFragmentManager();
if (fragmentManager.findFragmentByTag(detailsFragment ) == null) {
Log.d(TAG , "Adding current new fragment");
FragmentTransaction transaction = fragmentManager.beginTransaction();
ProfileDetailsFragment details = new ProfileDetailsFragment();
transaction.add(R.id.profile_details, details, detailsFragment);
transaction.commit();
}
}
}

View file

@ -0,0 +1,61 @@
package com.newsblur.domain;
import com.google.gson.annotations.SerializedName;
public class UserProfile {
public String username;
public String website;
public String bio;
public String location;
public String id;
@SerializedName("following_user_ids")
public int[] followingUserIds;
@SerializedName("follower_user_ids")
public int[] followerUserIds;
@SerializedName("num_subscribers")
public int numberOfSubscribers;
@SerializedName("average_stories_per_month")
public int averageStoriesPerMonth;
@SerializedName("following_count")
public int followingCount;
@SerializedName("feed_address")
public String feedAddress;
@SerializedName("subscription_count")
public int subscriptionCount;
@SerializedName("feed_title")
public String feedTitle;
@SerializedName("shared_stories_count")
public int sharedStoriesCount;
@SerializedName("photo_service")
public String photoService;
@SerializedName("stories_last_month")
public int storiesLastMonth;
@SerializedName("follower_count")
public int followerCount;
@SerializedName("user_id")
public int userId;
@SerializedName("feed_link")
public String feedLink;
@SerializedName("popular_publishers")
public String popularPublishers;
@SerializedName("photo_url")
public String photoUrl;
}

View file

@ -27,6 +27,7 @@ import com.newsblur.R;
import com.newsblur.activity.Main;
import com.newsblur.network.APIManager;
import com.newsblur.network.domain.LoginResponse;
import com.newsblur.network.domain.ProfileResponse;
import com.newsblur.service.DetachableResultReceiver;
import com.newsblur.service.DetachableResultReceiver.Receiver;
import com.newsblur.service.SyncService;
@ -119,6 +120,7 @@ public class LoginFragment extends Fragment implements OnClickListener, Receiver
final String username = params[0];
final String password = params[1];
LoginResponse response = apiManager.login(username, password);
apiManager.updateUserProfile();
try {
// We include this wait simply as a small UX convenience. Otherwise the user could be met with a disconcerting flicker when attempting to log in and failing.
Thread.sleep(700);

View file

@ -0,0 +1,25 @@
package com.newsblur.fragment;
import com.newsblur.R;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class ProfileDetailsFragment extends Fragment {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_profiledetails, null);
return v;
}
}

View file

@ -12,6 +12,8 @@ import java.util.List;
import java.util.Map.Entry;
import java.util.Scanner;
import com.newsblur.activity.PrefConstants;
import android.content.ContentValues;
import android.content.Context;
import android.content.SharedPreferences;
@ -33,8 +35,8 @@ public class APIClient {
try {
final URL urlFeeds = new URL(urlString);
connection = (HttpURLConnection) urlFeeds.openConnection();
final SharedPreferences preferences = context.getSharedPreferences(APIConstants.PREFERENCES, 0);
final String cookie = preferences.getString(APIConstants.PREF_COOKIE, null);
final SharedPreferences preferences = context.getSharedPreferences(PrefConstants.PREFERENCES, 0);
final String cookie = preferences.getString(PrefConstants.PREF_COOKIE, null);
if (cookie != null) {
connection.setRequestProperty("Cookie", cookie);
}

View file

@ -3,13 +3,14 @@ package com.newsblur.network;
public class APIConstants {
public static final String URL_LOGIN = "http://newsblur.com/api/login";
public static final String URL_FEEDS = "http://newsblur.com/reader/feeds/?include_favicons=true";
public static final String URL_LOGIN = "http://dev.newsblur.com/api/login";
public static final String URL_FEEDS = "http://dev.newsblur.com/reader/feeds/?include_favicons=true";
public static final String URL_USER_PROFILE = "http://dev.newsblur.com/social/load_user_profile";
public static final String USERNAME = "username";
public static final String PASSWORD = "password";
public static final String PREFERENCES = "preferences";
public static final String PREF_COOKIE = "login_cookie";
}

View file

@ -17,22 +17,22 @@ import com.google.gson.GsonBuilder;
import com.newsblur.database.DatabaseConstants;
import com.newsblur.database.FeedProvider;
import com.newsblur.domain.Feed;
import com.newsblur.domain.FeedUpdate;
import com.newsblur.domain.FolderStructure;
import com.newsblur.network.domain.FeedFolderResponse;
import com.newsblur.network.domain.LoginResponse;
import com.newsblur.network.domain.ProfileResponse;
import com.newsblur.serialization.FolderStructureTypeAdapter;
import com.newsblur.util.PrefsUtil;
public class APIManager {
private static final String TAG = "APIManager";
private Context context;
private SharedPreferences preferences;
private Gson gson;
private ContentResolver contentResolver;
public APIManager(final Context context) {
this.context = context;
preferences = context.getSharedPreferences(APIConstants.PREFERENCES, 0);
final GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(FolderStructure.class, new FolderStructureTypeAdapter());
contentResolver = context.getContentResolver();
@ -45,29 +45,38 @@ public class APIManager {
values.put(APIConstants.USERNAME, username);
values.put(APIConstants.PASSWORD, password);
final APIResponse response = client.post(APIConstants.URL_LOGIN, values);
if (response.responseCode == HttpStatus.SC_OK && response.hasRedirected == false) {
if (response.responseCode == HttpStatus.SC_OK && !response.hasRedirected) {
LoginResponse loginResponse = gson.fromJson(response.responseString, LoginResponse.class);
final Editor edit = preferences.edit();
edit.putString(APIConstants.PREF_COOKIE, response.cookie);
edit.commit();
PrefsUtil.saveCookie(context, response.cookie);
return loginResponse;
} else {
return new LoginResponse();
}
}
public boolean updateUserProfile() {
final APIClient client = new APIClient(context);
final APIResponse response = client.get(APIConstants.URL_USER_PROFILE);
if (response.responseCode == HttpStatus.SC_OK && !response.hasRedirected) {
ProfileResponse profileResponse = gson.fromJson(response.responseString, ProfileResponse.class);
PrefsUtil.saveUserDetails(context, profileResponse.user);
return true;
} else {
return false;
}
}
public void getFolderFeedMapping() {
final APIClient client = new APIClient(context);
final APIResponse response = client.get(APIConstants.URL_FEEDS);
final FeedUpdate feedUpdate = gson.fromJson(response.responseString, FeedUpdate.class);
final FeedFolderResponse feedUpdate = gson.fromJson(response.responseString, FeedFolderResponse.class);
for (Entry<String, Feed> entry : feedUpdate.feeds.entrySet()) {
final Feed feed = entry.getValue();
contentResolver.insert(FeedProvider.FEEDS_URI, feed.getValues());
}
for (Entry<String, List<Long>> entry : feedUpdate.folderStructure.folders.entrySet()) {
for (Entry<String, List<Long>> entry : feedUpdate.folderStructure.folders.entrySet()) {
final ContentValues folderValues = new ContentValues();
folderValues.put(DatabaseConstants.FOLDER_NAME, entry.getKey());
contentResolver.insert(FeedProvider.FOLDERS_URI, folderValues);
@ -79,9 +88,6 @@ public class APIManager {
contentResolver.insert(FeedProvider.FEED_FOLDER_MAP_URI, values);
}
}
Log.d(TAG, "Retrieved feeds");
}
}

View file

@ -1,10 +1,12 @@
package com.newsblur.domain;
package com.newsblur.network.domain;
import java.util.Map;
import com.google.gson.annotations.SerializedName;
import com.newsblur.domain.Feed;
import com.newsblur.domain.FolderStructure;
public class FeedUpdate {
public class FeedFolderResponse {
@SerializedName("starred_count")
public int starredCount;

View file

@ -0,0 +1,11 @@
package com.newsblur.network.domain;
import com.google.gson.annotations.SerializedName;
import com.newsblur.domain.UserProfile;
public class ProfileResponse {
@SerializedName("user_profile")
public UserProfile user;
}

View file

@ -0,0 +1,43 @@
package com.newsblur.util;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import com.newsblur.activity.PrefConstants;
import com.newsblur.domain.UserProfile;
public class PrefsUtil {
public static void saveCookie(final Context context, final String cookie) {
final SharedPreferences preferences = context.getSharedPreferences(PrefConstants.PREFERENCES, 0);
final Editor edit = preferences.edit();
edit.putString(PrefConstants.PREF_COOKIE, cookie);
edit.commit();
}
public static void saveUserDetails(final Context context, final UserProfile profile) {
final SharedPreferences preferences = context.getSharedPreferences(PrefConstants.PREFERENCES, 0);
final Editor edit = preferences.edit();
edit.putInt(PrefConstants.USER_AVERAGE_STORIES_PER_MONTH, profile.averageStoriesPerMonth);
edit.putString(PrefConstants.USER_BIO, profile.bio);
edit.putString(PrefConstants.USER_FEED_ADDRESS, profile.feedAddress);
edit.putString(PrefConstants.USER_FEED_TITLE, profile.feedTitle);
edit.putInt(PrefConstants.USER_FOLLOWER_COUNT, profile.followerCount);
edit.putInt(PrefConstants.USER_FOLLOWING_COUNT, profile.followingCount);
edit.putString(PrefConstants.USER_ID, profile.id);
edit.putString(PrefConstants.USER_LOCATION, profile.location);
edit.putString(PrefConstants.USER_PHOTO_SERVICE, profile.photoService);
edit.putString(PrefConstants.USER_PHOTO_URL, profile.photoUrl);
edit.putString(PrefConstants.USER_POPULAR_PUBLISHERS, profile.popularPublishers);
edit.putInt(PrefConstants.USER_SHARED_STORIES_COUNT, profile.sharedStoriesCount);
edit.putInt(PrefConstants.USER_STORIES_LAST_MONTH, profile.storiesLastMonth);
edit.putInt(PrefConstants.USER_STORIES_LAST_MONTH, profile.storiesLastMonth);
edit.putInt(PrefConstants.USER_SUBSCRIBER_COUNT, profile.subscriptionCount);
edit.putString(PrefConstants.USER_USERNAME, profile.username);
edit.putString(PrefConstants.USER_WEBSITE, profile.website);
edit.commit();
}
}