diff --git a/app/build.gradle b/app/build.gradle index ef1aaad..b239a69 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -26,4 +26,5 @@ dependencies { compile 'com.android.support:support-v4:19.+' compile 'com.android.support:appcompat-v7:19.+' compile 'com.github.chrisbanes.actionbarpulltorefresh:extra-abc:+' + compile 'com.mcxiaoke.viewpagerindicator:library:2.4.1' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index e4b06b7..a8a68c9 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -27,6 +27,13 @@ + + + diff --git a/app/src/main/java/i2p/bote/android/EmailListActivity.java b/app/src/main/java/i2p/bote/android/EmailListActivity.java index 4d6a808..2900a37 100644 --- a/app/src/main/java/i2p/bote/android/EmailListActivity.java +++ b/app/src/main/java/i2p/bote/android/EmailListActivity.java @@ -1,23 +1,9 @@ package i2p.bote.android; -import net.i2p.android.router.service.IRouterState; -import i2p.bote.I2PBote; -import i2p.bote.android.addressbook.AddressBookActivity; -import i2p.bote.android.config.SettingsActivity; -import i2p.bote.android.service.BoteService; -import i2p.bote.android.service.Init; -import i2p.bote.android.service.Init.RouterChoice; -import i2p.bote.android.util.MoveToDialogFragment; -import i2p.bote.folder.EmailFolder; -import android.os.Bundle; -import android.os.IBinder; -import android.os.RemoteException; -import android.preference.PreferenceManager; -import android.app.Activity; import android.app.ActivityManager; +import android.app.ActivityManager.RunningServiceInfo; import android.app.AlertDialog; import android.app.Dialog; -import android.app.ActivityManager.RunningServiceInfo; import android.content.ComponentName; import android.content.Context; import android.content.DialogInterface; @@ -26,6 +12,10 @@ import android.content.ServiceConnection; import android.content.SharedPreferences; import android.content.res.Configuration; import android.graphics.drawable.Drawable; +import android.os.Bundle; +import android.os.IBinder; +import android.os.RemoteException; +import android.preference.PreferenceManager; import android.support.v4.app.ActionBarDrawerToggle; import android.support.v4.app.DialogFragment; import android.support.v4.view.GravityCompat; @@ -38,6 +28,19 @@ import android.widget.AdapterView; import android.widget.ListView; import android.widget.RelativeLayout; import android.widget.TextView; +import android.widget.Toast; + +import net.i2p.android.router.service.IRouterState; + +import i2p.bote.I2PBote; +import i2p.bote.android.addressbook.AddressBookActivity; +import i2p.bote.android.config.SettingsActivity; +import i2p.bote.android.intro.IntroActivity; +import i2p.bote.android.service.BoteService; +import i2p.bote.android.service.Init; +import i2p.bote.android.service.Init.RouterChoice; +import i2p.bote.android.util.MoveToDialogFragment; +import i2p.bote.folder.EmailFolder; public class EmailListActivity extends ActionBarActivity implements EmailListFragment.OnEmailSelectedListener, @@ -60,9 +63,11 @@ public class EmailListActivity extends ActionBarActivity implements private static final String SHARED_PREFS = "i2p.bote"; private static final String PREF_NAV_DRAWER_OPENED = "navDrawerOpened"; + private static final String PREF_FIRST_START = "firstStart"; private static final String ACTIVE_FOLDER = "activeFolder"; - private static final int REQUEST_START_I2P = 1; + private static final int RUN_SETUP_WIZARD = 1; + private static final int REQUEST_START_I2P = 2; @Override protected void onCreate(Bundle savedInstanceState) { @@ -206,6 +211,14 @@ public class EmailListActivity extends ActionBarActivity implements // Open nav drawer if the user has never opened it themselves if (!mSharedPrefs.getBoolean(PREF_NAV_DRAWER_OPENED, false)) mDrawerLayout.openDrawer(mDrawerOuter); + + // If first start, go to introduction and setup wizard + // TODO always show while testing, revert to preference when finished + if (true || mSharedPrefs.getBoolean(PREF_FIRST_START, true)) { + mSharedPrefs.edit().putBoolean(PREF_FIRST_START, false).apply(); + Intent i = new Intent(EmailListActivity.this, IntroActivity.class); + startActivityForResult(i, RUN_SETUP_WIZARD); + } } private class DrawerItemClickListener implements ListView.OnItemClickListener { @@ -353,8 +366,13 @@ public class EmailListActivity extends ActionBarActivity implements @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { - if (requestCode == REQUEST_START_I2P) { - if (resultCode == Activity.RESULT_OK) { + if (requestCode == RUN_SETUP_WIZARD) { + if (resultCode == RESULT_OK) { + // TODO remove (and implement a UI tutorial?) + Toast.makeText(this, "Setup wizard not yet implemented.", Toast.LENGTH_SHORT).show(); + } + } else if (requestCode == REQUEST_START_I2P) { + if (resultCode == RESULT_OK) { startBote(); } } else { diff --git a/app/src/main/java/i2p/bote/android/intro/IntroActivity.java b/app/src/main/java/i2p/bote/android/intro/IntroActivity.java new file mode 100644 index 0000000..e6debe2 --- /dev/null +++ b/app/src/main/java/i2p/bote/android/intro/IntroActivity.java @@ -0,0 +1,144 @@ +package i2p.bote.android.intro; + +import android.app.Activity; +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentManager; +import android.support.v4.app.FragmentPagerAdapter; +import android.support.v4.view.ViewPager; +import android.support.v7.app.ActionBarActivity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.TextView; + +import com.viewpagerindicator.LinePageIndicator; + +import i2p.bote.android.R; + +public class IntroActivity extends ActionBarActivity { + + /** + * The {@link android.support.v4.view.PagerAdapter} that will provide + * fragments for each of the sections. We use a + * {@link FragmentPagerAdapter} derivative, which will keep every + * loaded fragment in memory. If this becomes too memory intensive, it + * may be best to switch to a + * {@link android.support.v4.app.FragmentStatePagerAdapter}. + */ + SectionsPagerAdapter mSectionsPagerAdapter; + + /** + * The {@link ViewPager} that will host the section contents. + */ + ViewPager mViewPager; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_intro); + + // Take up the entire screen. + getSupportActionBar().hide(); + + // Create the sections adapter. + mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager()); + + // Set up the ViewPager with the sections adapter. + mViewPager = (ViewPager) findViewById(R.id.pager); + mViewPager.setAdapter(mSectionsPagerAdapter); + + // Bind the page indicator to the pager. + LinePageIndicator pageIndicator = (LinePageIndicator)findViewById(R.id.page_indicator); + pageIndicator.setViewPager(mViewPager); + + findViewById(R.id.skip_intro).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + setResult(Activity.RESULT_CANCELED); + finish(); + } + }); + } + + + /** + * A {@link FragmentPagerAdapter} that returns a fragment corresponding to + * one of the intro sections. + */ + public class SectionsPagerAdapter extends FragmentPagerAdapter { + + public SectionsPagerAdapter(FragmentManager fm) { + super(fm); + } + + @Override + public Fragment getItem(int position) { + // getItem is called to instantiate the fragment for the given page. + // Return a PlaceholderFragment (defined as a static inner class below). + return PlaceholderFragment.newInstance(position); + } + + @Override + public int getCount() { + return 5; + } + } + + /** + * A placeholder fragment containing a simple view. + */ + public static class PlaceholderFragment extends Fragment { + /** + * The fragment argument representing the section number for this + * fragment. + */ + private static final String ARG_SECTION_NUMBER = "section_number"; + + /** + * Returns a new instance of this fragment for the given section + * number. + */ + public static PlaceholderFragment newInstance(int sectionNumber) { + PlaceholderFragment fragment = new PlaceholderFragment(); + Bundle args = new Bundle(); + args.putInt(ARG_SECTION_NUMBER, sectionNumber); + fragment.setArguments(args); + return fragment; + } + + public PlaceholderFragment() { + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + switch (getArguments().getInt(ARG_SECTION_NUMBER)) { + case 1: + return inflater.inflate(R.layout.fragment_intro_1, container, false); + case 2: + return inflater.inflate(R.layout.fragment_intro_2, container, false); + case 3: + return inflater.inflate(R.layout.fragment_intro_3, container, false); + case 4: + View v4 = inflater.inflate(R.layout.fragment_intro_4, container, false); + Button b = (Button) v4.findViewById(R.id.start_setup_wizard); + b.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + // TODO start setup wizard + getActivity().setResult(Activity.RESULT_OK); + getActivity().finish(); + } + }); + return v4; + default: + View v0 = inflater.inflate(R.layout.fragment_intro_0, container, false); + TextView tv = (TextView) v0.findViewById(R.id.intro_app_name); + tv.append("."); + return v0; + } + } + } +} diff --git a/app/src/main/res/drawable-hdpi/ic_navigation_back.png b/app/src/main/res/drawable-hdpi/ic_navigation_back.png new file mode 100644 index 0000000..837998f Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_navigation_back.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_navigation_back.png b/app/src/main/res/drawable-mdpi/ic_navigation_back.png new file mode 100644 index 0000000..e6ba4a8 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_navigation_back.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_navigation_back.png b/app/src/main/res/drawable-xhdpi/ic_navigation_back.png new file mode 100644 index 0000000..f420e43 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_navigation_back.png differ diff --git a/app/src/main/res/layout/activity_intro.xml b/app/src/main/res/layout/activity_intro.xml new file mode 100644 index 0000000..0bacb07 --- /dev/null +++ b/app/src/main/res/layout/activity_intro.xml @@ -0,0 +1,28 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_intro_0.xml b/app/src/main/res/layout/fragment_intro_0.xml new file mode 100644 index 0000000..e3cbd75 --- /dev/null +++ b/app/src/main/res/layout/fragment_intro_0.xml @@ -0,0 +1,53 @@ + + + + + + + + + + + + diff --git a/app/src/main/res/layout/fragment_intro_1.xml b/app/src/main/res/layout/fragment_intro_1.xml new file mode 100644 index 0000000..d7555aa --- /dev/null +++ b/app/src/main/res/layout/fragment_intro_1.xml @@ -0,0 +1,40 @@ + + + + + + + + diff --git a/app/src/main/res/layout/fragment_intro_2.xml b/app/src/main/res/layout/fragment_intro_2.xml new file mode 100644 index 0000000..68d7042 --- /dev/null +++ b/app/src/main/res/layout/fragment_intro_2.xml @@ -0,0 +1,40 @@ + + + + + + + + diff --git a/app/src/main/res/layout/fragment_intro_3.xml b/app/src/main/res/layout/fragment_intro_3.xml new file mode 100644 index 0000000..757d871 --- /dev/null +++ b/app/src/main/res/layout/fragment_intro_3.xml @@ -0,0 +1,40 @@ + + + + + + + + diff --git a/app/src/main/res/layout/fragment_intro_4.xml b/app/src/main/res/layout/fragment_intro_4.xml new file mode 100644 index 0000000..6ed512c --- /dev/null +++ b/app/src/main/res/layout/fragment_intro_4.xml @@ -0,0 +1,49 @@ + + + + + + + + +