package org.theotech.ceaselessandroid.activity;
import android.Manifest;
import android.app.Fragment;
import android.app.backup.BackupManager;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.support.annotation.NonNull;
import android.support.design.widget.NavigationView;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.MenuItem;
import android.widget.ImageView;
import android.widget.Toast;
import org.codechimp.apprater.AppRater;
import org.theotech.ceaselessandroid.R;
import org.theotech.ceaselessandroid.fragment.AddNoteFragment;
import org.theotech.ceaselessandroid.fragment.FragmentBackStackManager;
import org.theotech.ceaselessandroid.fragment.FragmentState;
import org.theotech.ceaselessandroid.fragment.FragmentStateListener;
import org.theotech.ceaselessandroid.fragment.HomeFragment;
import org.theotech.ceaselessandroid.fragment.PeopleFragment;
import org.theotech.ceaselessandroid.notification.DailyNotificationReceiver;
import org.theotech.ceaselessandroid.person.PersonManagerImpl;
import org.theotech.ceaselessandroid.tutorial.HomeTutorialFragment;
import org.theotech.ceaselessandroid.tutorial.Tutorial;
import org.theotech.ceaselessandroid.util.CommonUtils;
import org.theotech.ceaselessandroid.util.Constants;
import org.theotech.ceaselessandroid.util.FragmentUtils;
import butterknife.Bind;
import butterknife.ButterKnife;
public class MainActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener,
FragmentStateListener,
ActivityCompat.OnRequestPermissionsResultCallback {
private static final String TAG = MainActivity.class.getSimpleName();
private static final int POPULATE_CONTACTS_REQUEST_CODE = 1;
private static final int ADD_CONTACT_REQUEST_CODE = 2;
private boolean homeFragmentCreated = false;
@Bind(R.id.toolbar)
Toolbar toolbar;
@Bind(R.id.drawer_layout)
DrawerLayout drawer;
@Bind(R.id.nav_view)
NavigationView navigation;
@Bind(R.id.backgroundImageView)
ImageView backgroundImageView;
private FragmentBackStackManager backStackManager;
private FragmentState currentFragment;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState != null) {
Log.d(TAG, "reloading from savedInstanceState " + savedInstanceState);
} else {
Log.d(TAG, "Starting activity fresh");
}
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
setSupportActionBar(toolbar);
navigation.setCheckedItem(R.id.nav_home);
navigation.setNavigationItemSelectedListener(this);
populateContacts();
setNotification();
CommonUtils.setupBackgroundImage(this, backgroundImageView);
// initialize the back stack
backStackManager = new FragmentBackStackManager();
// if we were called with a special action, load the right fragment
Intent intent = getIntent();
handleIntent(intent);
// TODO decide if we want to use AppRater's logic to surface a review request
// AppRater.app_launched(this);
}
@Override
protected void onNewIntent(Intent intent) {
handleIntent(intent);
super.onNewIntent(intent);
}
private void handleIntent(Intent intent) {
// if we were called with a special action, load the right fragment
if (Constants.SHOW_PERSON_INTENT.equals(intent.getAction())) {
PeopleFragment peopleFragment = new PeopleFragment();
peopleFragment.setArguments(intent.getExtras());
getFragmentManager().beginTransaction().replace(R.id.fragment, peopleFragment,
getString(R.string.nav_people)).commit();
} else if (Constants.SHOW_NOTE_INTENT.equals(intent.getAction())) {
AddNoteFragment addNoteFragment = new AddNoteFragment();
addNoteFragment.setArguments(intent.getExtras());
getFragmentManager().beginTransaction().replace(R.id.fragment, addNoteFragment,
getString(R.string.nav_journal)).commit();
} else if (Tutorial.shouldShowTutorial(this)) {
//loadHomeTutorialFragment();
// We are testing to see response rates when we disable the tutorial and jump
// straight to the main screen.
Log.i(TAG, "Skipping tutorial for testing user response.");
loadMainFragment();
} else {
loadMainFragment();
}
}
/**
* Requests a backup operation to be done.
*/
public void requestBackup() {
BackupManager bm = new BackupManager(this);
Log.i(TAG, "Backing up database and preferences");
bm.dataChanged();
}
/**
* Get a variable representing whether or not this activity
* has ever created a {@link HomeFragment}.
* The HomeFragment tracks which page it is on and returns to that
* page when it is recreated unless the MainActivity has never created it before.
* So for example, when a user starts the app, HomeFragment starts on the first page,
* but when the user returns to Home from an AddNote fragment, it returns to the page
* the user was on.
* @return true if this activity has created a HomeFragment before, false otherwise.
*/
public boolean getHomeFragmentCreated() {
return homeFragmentCreated;
}
public void setHomeFragmentCreated(boolean homeFragmentCreated) {
this.homeFragmentCreated = homeFragmentCreated;
}
public void loadMainFragment() {
getFragmentManager().beginTransaction().replace(R.id.fragment, new HomeFragment(),
getString(R.string.nav_home)).commit();
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawer.setDrawerListener(toggle);
drawer.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
toggle.syncState();
// TODO when do we request backups?
requestBackup();
}
public void loadHomeTutorialFragment() {
Fragment frag = new HomeTutorialFragment();
String title = getString(R.string.nav_home_tutorial);
getFragmentManager().beginTransaction().replace(R.id.fragment, frag, title).commit();
drawer.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
@NonNull int[] grantResults) {
switch (requestCode) {
case POPULATE_CONTACTS_REQUEST_CODE:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
PersonManagerImpl.getInstance(this).populateContacts();
} else {
// Permission Denied
Toast.makeText(MainActivity.this, getString(R.string.contacts_access_required),
Toast.LENGTH_SHORT).show();
}
break;
default:
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
@Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else {
if (!backStackManager.isEmpty()) {
FragmentState fragmentState = backStackManager.pop();
FragmentUtils.loadFragment(this, getFragmentManager(), navigation, FragmentUtils.getNavigationItemIdForFragmentName(this, fragmentState.getFragmentName()),
fragmentState.getState());
} else {
super.onBackPressed();
}
}
}
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
// handle navigation view item clicks here
int id = item.getItemId();
if (id == R.id.nav_rate_this_app) { // easter egg - option to load home fragment without using cache data
// rate my app dialog
AppRater.rateNow(this);
} else if (id == R.id.nav_subscribe_to_newsletter) {
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.mailing_list_url)));
if (intent.resolveActivity(getPackageManager()) != null) {
startActivity(intent);
}
} else {
// replace fragment if it's not already visible
FragmentUtils.loadFragment(this, getFragmentManager(), navigation, id, currentFragment);
}
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// 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.person_add_note) {
FragmentUtils.loadFragment(this, getFragmentManager(), navigation, id, currentFragment.getState(),
currentFragment);
return true;
}
if (id == R.id.add_contact) {
Intent intent = new Intent(ContactsContract.Intents.Insert.ACTION);
intent.setType(ContactsContract.RawContacts.CONTENT_TYPE);
startActivityForResult(intent, ADD_CONTACT_REQUEST_CODE);
return true;
}
if (id == R.id.sync_contacts) {
// Permission Denied
Toast.makeText(MainActivity.this, getString(R.string.syncing_contacts),
Toast.LENGTH_SHORT).show();
populateContacts();
}
return super.onOptionsItemSelected(item);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == ADD_CONTACT_REQUEST_CODE) {
// pick up any new contacts that have been added.
// TODO make this more efficient by adding just the one that has been added.
// I did this because I noticed that the data was coming back null even though a contact was added.
// Also right now the populateContacts has a filtering logic and so if they add a contact
// without email or phone number, it still won't show up in Ceaseless unfortunately.
populateContacts();
}
}
public FragmentBackStackManager getFragmentBackStackManager() {
return backStackManager;
}
@Override
public void notify(FragmentState fragmentState) {
// update current fragment
currentFragment = fragmentState;
}
private void populateContacts() {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS)
!= PackageManager.PERMISSION_GRANTED) {
// Should we show an explanation?
if (ActivityCompat.shouldShowRequestPermissionRationale(
this, Manifest.permission.READ_CONTACTS)) {
Log.d(TAG, "Should show rationale");
// From the developers handbook:
// Show an explanation to the user *asynchronously* -- don't block
// this thread waiting for the user's response! After the user
// sees the explanation, try again to request the permission.
showMessageOKCancel(getString(R.string.contacts_access_required),
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
ActivityCompat.requestPermissions(MainActivity.this,
new String[]{Manifest.permission.READ_CONTACTS},
POPULATE_CONTACTS_REQUEST_CODE);
}
});
} else {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.READ_CONTACTS},
POPULATE_CONTACTS_REQUEST_CODE);
}
return;
}
PersonManagerImpl.getInstance(this).populateContacts();
}
private void showMessageOKCancel(String message, DialogInterface.OnClickListener okListener) {
new AlertDialog.Builder(this, R.style.AlertDialogTheme)
.setMessage(message)
.setPositiveButton(getString(android.R.string.ok), okListener)
.create()
.show();
}
private void setNotification() {
Intent dailyNotificationReceiver = new Intent(getApplicationContext(), DailyNotificationReceiver.class);
getApplicationContext().sendBroadcast(dailyNotificationReceiver);
}
}