Changed directory structure
1
app/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/build
|
BIN
app/app-release.apk
Normal file
33
app/build.gradle
Normal file
@@ -0,0 +1,33 @@
|
||||
apply plugin: 'com.android.application'
|
||||
|
||||
android {
|
||||
compileSdkVersion 27
|
||||
buildToolsVersion '26.0.2'
|
||||
|
||||
defaultConfig {
|
||||
applicationId "com.wismna.geoffroy.donext"
|
||||
minSdkVersion 19
|
||||
targetSdkVersion 27
|
||||
versionCode 23
|
||||
versionName "1.4.8"
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile fileTree(dir: 'libs', include: ['*.jar'])
|
||||
compile 'com.android.support:appcompat-v7:27.0.2'
|
||||
compile 'com.android.support:design:27.0.2'
|
||||
compile 'com.android.support:support-v4:27.0.2'
|
||||
compile 'com.android.support:percent:27.0.2'
|
||||
compile 'com.android.support:recyclerview-v7:27.0.2'
|
||||
compile 'com.google.android.gms:play-services-ads:11.6.2'
|
||||
compile 'net.danlew:android.joda:2.9.7'
|
||||
compile 'com.android.support.constraint:constraint-layout:1.0.2'
|
||||
testCompile 'junit:junit:4.12'
|
||||
}
|
17
app/proguard-rules.pro
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# By default, the flags in this file are appended to flags specified
|
||||
# in /opt/Android/Sdk/tools/proguard/proguard-android.txt
|
||||
# You can edit the include path and order by changing the proguardFiles
|
||||
# directive in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# Add any project specific keep options here:
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
65
app/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1,65 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.wismna.geoffroy.donext">
|
||||
|
||||
<application
|
||||
android:name=".DoNext"
|
||||
android:allowBackup="true"
|
||||
android:fullBackupContent="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme">
|
||||
<meta-data
|
||||
android:name="android.max_aspect"
|
||||
android:value="2.1" />
|
||||
|
||||
<activity
|
||||
android:name=".activities.MainActivity"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/AppTheme.NoActionBar"
|
||||
android:windowSoftInputMode="stateAlwaysHidden">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".activities.SettingsActivity"
|
||||
android:label="@string/action_settings"
|
||||
android:parentActivityName=".activities.MainActivity">
|
||||
<meta-data
|
||||
android:name="android.support.PARENT_ACTIVITY"
|
||||
android:value=".activities.MainActivity" />
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".activities.TaskListActivity"
|
||||
android:label="@string/action_editTabs"
|
||||
android:parentActivityName=".activities.MainActivity">
|
||||
<meta-data
|
||||
android:name="android.support.PARENT_ACTIVITY"
|
||||
android:value=".activities.MainActivity" />
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".activities.AboutActivity"
|
||||
android:label="@string/action_about"
|
||||
android:parentActivityName=".activities.MainActivity">
|
||||
<meta-data
|
||||
android:name="android.support.PARENT_ACTIVITY"
|
||||
android:value=".activities.MainActivity" />
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".activities.TodayActivity"
|
||||
android:label="@string/title_activity_today"
|
||||
android:parentActivityName=".activities.MainActivity"
|
||||
android:theme="@style/AppTheme.NoActionBar">
|
||||
<meta-data
|
||||
android:name="android.support.PARENT_ACTIVITY"
|
||||
android:value=".activities.MainActivity" />
|
||||
</activity>
|
||||
<activity android:name=".activities.HistoryActivity" />
|
||||
</application>
|
||||
|
||||
</manifest>
|
BIN
app/src/main/ic_launcher-web.png
Normal file
After Width: | Height: | Size: 12 KiB |
18
app/src/main/java/com/wismna/geoffroy/donext/DoNext.java
Normal file
@@ -0,0 +1,18 @@
|
||||
package com.wismna.geoffroy.donext;
|
||||
|
||||
import android.app.Application;
|
||||
|
||||
import net.danlew.android.joda.JodaTimeAndroid;
|
||||
|
||||
/**
|
||||
* Created by bg45 on 2017-03-15.
|
||||
* Application class, used to initialize Joda Time
|
||||
*/
|
||||
|
||||
public class DoNext extends Application {
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
JodaTimeAndroid.init(this);
|
||||
}
|
||||
}
|
@@ -0,0 +1,25 @@
|
||||
package com.wismna.geoffroy.donext.activities;
|
||||
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.wismna.geoffroy.donext.BuildConfig;
|
||||
import com.wismna.geoffroy.donext.R;
|
||||
|
||||
public class AboutActivity extends AppCompatActivity {
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_about);
|
||||
|
||||
TextView versionDonext = (TextView) findViewById(R.id.version_donext);
|
||||
versionDonext.setText(getResources().getString(R.string.about_version_donext, BuildConfig.VERSION_NAME));
|
||||
|
||||
TextView versionAndroid = (TextView) findViewById(R.id.version_android);
|
||||
versionAndroid.setText(getResources().getString(R.string.about_version_android, Build.VERSION.SDK_INT));
|
||||
|
||||
}
|
||||
}
|
@@ -0,0 +1,171 @@
|
||||
package com.wismna.geoffroy.donext.activities;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.v4.app.FragmentManager;
|
||||
import android.support.v4.app.FragmentTransaction;
|
||||
import android.support.v4.view.ViewPager;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
|
||||
import com.wismna.geoffroy.donext.R;
|
||||
import com.wismna.geoffroy.donext.fragments.MainFragment;
|
||||
import com.wismna.geoffroy.donext.fragments.TaskFormDialogFragment;
|
||||
import com.wismna.geoffroy.donext.fragments.TaskListsFragment;
|
||||
import com.wismna.geoffroy.donext.fragments.TasksFragment;
|
||||
|
||||
/**
|
||||
* Main Activity class
|
||||
*/
|
||||
public class MainActivity extends AppCompatActivity {
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_main);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPrepareOptionsMenu(Menu menu) {
|
||||
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
|
||||
// Handles today list
|
||||
MenuItem todayListItem = menu.findItem(R.id.action_todayList);
|
||||
if (todayListItem == null) return false;
|
||||
todayListItem.setVisible(sharedPref.getBoolean("pref_conf_today_enable", false));
|
||||
|
||||
return super.onPrepareOptionsMenu(menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
// Inflate the menu; this adds items to the action bar if it is present.
|
||||
getMenuInflater().inflate(R.menu.menu_main, menu);
|
||||
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();
|
||||
|
||||
return id == R.id.action_settings || super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
/** Called when the user clicks on the Today List button */
|
||||
public void showTodayList(MenuItem item) {
|
||||
Intent intent = new Intent(this, TodayActivity.class);
|
||||
startActivity(intent);
|
||||
}
|
||||
|
||||
/** Called when the user clicks on the Change Layout button */
|
||||
public void changeLayout(MenuItem item) {
|
||||
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
SharedPreferences.Editor editor = sharedPref.edit();
|
||||
String layoutTypeString = sharedPref.getString("pref_conf_task_layout", "1");
|
||||
int layoutType = Integer.valueOf(layoutTypeString);
|
||||
editor.putString("pref_conf_task_layout", String.valueOf(layoutType % 2 + 1));
|
||||
editor.apply();
|
||||
|
||||
// Update the ViewPagerAdapter to refresh all tabs
|
||||
MainFragment fragment = getMainFragment();
|
||||
fragment.getViewPager().getAdapter().notifyDataSetChanged();
|
||||
//mSectionsPagerAdapter.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
/** Called when the user clicks the Edit Lists button */
|
||||
public void openTaskLists(MenuItem menuItem) {
|
||||
/*Intent intent = new Intent(this, TaskListActivity.class);
|
||||
startActivity(intent);*/
|
||||
// Create the fragment
|
||||
TaskListsFragment taskListFragment = new TaskListsFragment();
|
||||
String title = getString(R.string.action_edit_task);
|
||||
FragmentManager fragmentManager = getSupportFragmentManager();
|
||||
|
||||
// Set the arguments
|
||||
Bundle args = new Bundle();
|
||||
args.putInt("button_count", 1);
|
||||
args.putString("button_negative", getString(R.string.task_list_ok));
|
||||
taskListFragment.setArguments(args);
|
||||
|
||||
if (getResources().getBoolean(R.bool.large_layout))
|
||||
taskListFragment.show(fragmentManager, title);
|
||||
else {
|
||||
// The device is smaller, so show the fragment fullscreen
|
||||
FragmentTransaction transaction = fragmentManager.beginTransaction();
|
||||
// For a little polish, specify a transition animation
|
||||
transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
|
||||
// To make it fullscreen, use the 'content' root view as the container
|
||||
// for the fragment, which is always the root view for the activity
|
||||
transaction.add(android.R.id.content, taskListFragment, title)
|
||||
.addToBackStack(null).commit();
|
||||
}
|
||||
}
|
||||
|
||||
/** Called when the user clicks the History button*/
|
||||
public void openHistory(MenuItem item) {
|
||||
MainFragment fragment = getMainFragment();
|
||||
fragment.toggleHistory();
|
||||
}
|
||||
|
||||
/** Called when the user clicks the Settings button */
|
||||
public void openSettings(MenuItem menuItem) {
|
||||
Intent intent = new Intent(this, SettingsActivity.class);
|
||||
startActivity(intent);
|
||||
}
|
||||
|
||||
/** Called when the user clicks the About button */
|
||||
public void openAbout(MenuItem menuItem) {
|
||||
Intent intent = new Intent(this, AboutActivity.class);
|
||||
startActivity(intent);
|
||||
}
|
||||
|
||||
/** Called when user clicks on the New Task floating button */
|
||||
public void onNewTaskClick(View view) {
|
||||
|
||||
MainFragment fragment = getMainFragment();
|
||||
ViewPager viewPager = fragment.getViewPager();
|
||||
int currentTabPosition = viewPager.getCurrentItem();
|
||||
MainFragment.SectionsPagerAdapter pagerAdapter = (MainFragment.SectionsPagerAdapter) viewPager.getAdapter();
|
||||
TaskFormDialogFragment taskDialogFragment = TaskFormDialogFragment.newInstance(null,
|
||||
pagerAdapter.getAllItems(),
|
||||
(TasksFragment) pagerAdapter.getRegisteredFragment(currentTabPosition));
|
||||
|
||||
// Set some configuration values for the tab
|
||||
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
Bundle args = new Bundle();
|
||||
args.putInt("list", currentTabPosition);
|
||||
args.putBoolean("today", sharedPref.getBoolean("pref_conf_today_enable", false));
|
||||
args.putInt("button_count", 2);
|
||||
args.putString("button_positive", getString(R.string.new_task_save));
|
||||
args.putString("button_negative", getString(R.string.new_task_cancel));
|
||||
args.putString("button_neutral", getString(R.string.new_task_delete));
|
||||
taskDialogFragment.setArguments(args);
|
||||
|
||||
String title = getString(R.string.action_new_task);
|
||||
FragmentManager fragmentManager = getSupportFragmentManager();
|
||||
if (getResources().getBoolean(R.bool.large_layout))
|
||||
taskDialogFragment.show(fragmentManager, title);
|
||||
else {
|
||||
// The device is smaller, so show the fragment fullscreen
|
||||
FragmentTransaction transaction = fragmentManager.beginTransaction();
|
||||
// For a little polish, specify a transition animation
|
||||
transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
|
||||
// To make it fullscreen, use the 'content' root view as the container
|
||||
// for the fragment, which is always the root view for the activity
|
||||
transaction.add(android.R.id.content, taskDialogFragment, title)
|
||||
.addToBackStack(null).commit();
|
||||
}
|
||||
}
|
||||
|
||||
private MainFragment getMainFragment(){
|
||||
FragmentManager manager = getSupportFragmentManager();
|
||||
return (MainFragment)manager.findFragmentById(R.id.fragment_main);
|
||||
}
|
||||
}
|
@@ -0,0 +1,32 @@
|
||||
package com.wismna.geoffroy.donext.activities;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceFragment;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
|
||||
import com.wismna.geoffroy.donext.R;
|
||||
|
||||
public class SettingsActivity extends AppCompatActivity {
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
// Display the preferences fragment as the main content.
|
||||
getFragmentManager().beginTransaction()
|
||||
.replace(android.R.id.content, new SettingsFragment())
|
||||
.commit();
|
||||
PreferenceManager.setDefaultValues(this, R.xml.preferences, false);
|
||||
}
|
||||
|
||||
public static class SettingsFragment extends PreferenceFragment {
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
// Load the preferences from an XML resource
|
||||
addPreferencesFromResource(R.xml.preferences);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,14 @@
|
||||
package com.wismna.geoffroy.donext.activities;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
|
||||
import com.wismna.geoffroy.donext.R;
|
||||
|
||||
public class TaskListActivity extends AppCompatActivity{
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_tasklists);
|
||||
}
|
||||
}
|
@@ -0,0 +1,106 @@
|
||||
package com.wismna.geoffroy.donext.activities;
|
||||
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.design.widget.FloatingActionButton;
|
||||
import android.support.v4.app.FragmentManager;
|
||||
import android.support.v4.app.FragmentTransaction;
|
||||
import android.support.v7.app.ActionBar;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.support.v7.widget.Toolbar;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
|
||||
import com.wismna.geoffroy.donext.R;
|
||||
import com.wismna.geoffroy.donext.adapters.TaskRecyclerViewAdapter;
|
||||
import com.wismna.geoffroy.donext.database.TaskDataAccess;
|
||||
import com.wismna.geoffroy.donext.fragments.TodayFormDialogFragment;
|
||||
|
||||
public class TodayActivity extends AppCompatActivity
|
||||
implements TodayFormDialogFragment.TodayTaskListener {
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_today);
|
||||
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
|
||||
setSupportActionBar(toolbar);
|
||||
|
||||
// Get a support ActionBar corresponding to this toolbar
|
||||
ActionBar ab = getSupportActionBar();
|
||||
|
||||
if (ab != null) {
|
||||
// Enable the Up button
|
||||
ab.setDisplayHomeAsUpEnabled(true);
|
||||
ab.setHomeButtonEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
getMenuInflater().inflate(R.menu.menu_today, menu);
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Called when the user clicks on the Change Layout button */
|
||||
public void changeLayout(MenuItem item) {
|
||||
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
SharedPreferences.Editor editor = sharedPref.edit();
|
||||
String layoutTypeString = sharedPref.getString("pref_conf_task_layout", "1");
|
||||
int layoutType = Integer.valueOf(layoutTypeString);
|
||||
editor.putString("pref_conf_task_layout", String.valueOf(layoutType % 2 + 1));
|
||||
editor.apply();
|
||||
|
||||
// TODO: find a less ugly way to refresh the list
|
||||
// Update the ViewPagerAdapter to refresh all tabs
|
||||
this.recreate();
|
||||
}
|
||||
|
||||
|
||||
public void onNewTaskClick(View view) {
|
||||
TodayFormDialogFragment taskDialogFragment =
|
||||
TodayFormDialogFragment.newInstance(TodayActivity.this);
|
||||
|
||||
boolean isLargeLayout = getResources().getBoolean(R.bool.large_layout);
|
||||
// Set some configuration values for the dialog
|
||||
Bundle args = new Bundle();
|
||||
args.putBoolean("layout", isLargeLayout);
|
||||
args.putString("button_positive", getString(R.string.new_task_save));
|
||||
args.putString("button_negative", getString(R.string.new_task_cancel));
|
||||
taskDialogFragment.setArguments(args);
|
||||
|
||||
String title = getString(R.string.action_today_select);
|
||||
FragmentManager fragmentManager = getSupportFragmentManager();
|
||||
if (isLargeLayout)
|
||||
taskDialogFragment.show(fragmentManager, title);
|
||||
else {
|
||||
// The device is smaller, so show the fragment fullscreen
|
||||
FragmentTransaction transaction = fragmentManager.beginTransaction();
|
||||
// For a little polish, specify a transition animation
|
||||
transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
|
||||
// To make it fullscreen, use the 'content' root view as the container
|
||||
// for the fragment, which is always the root view for the activity
|
||||
transaction.add(android.R.id.content, taskDialogFragment, title)
|
||||
.addToBackStack(null).commit();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTodayTaskDialogPositiveClick(View dialogView) {
|
||||
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
|
||||
fab.setEnabled(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTodayTasksUpdated() {
|
||||
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
|
||||
fab.setEnabled(true);
|
||||
try (TaskDataAccess taskDataAccess = new TaskDataAccess(this)) {
|
||||
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.task_list_view);
|
||||
((TaskRecyclerViewAdapter)recyclerView.getAdapter()).setItems(taskDataAccess.getTodayTasks());
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,48 @@
|
||||
package com.wismna.geoffroy.donext.adapters;
|
||||
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v4.app.FragmentManager;
|
||||
import android.support.v4.app.FragmentStatePagerAdapter;
|
||||
import android.util.SparseArray;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
/**
|
||||
* Created by geoffroy on 15-11-28.
|
||||
* Extension of FragmentStatePagerAdapter which intelligently caches
|
||||
* all active fragments and manages the fragment lifecycles.
|
||||
* Usage involves extending from SmartFragmentStatePagerAdapter as you would any other PagerAdapter.
|
||||
*/
|
||||
|
||||
public abstract class SmartFragmentStatePagerAdapter extends FragmentStatePagerAdapter {
|
||||
// Sparse array to keep track of registered fragments in memory
|
||||
private final SparseArray<Fragment> registeredFragments = new SparseArray<>();
|
||||
|
||||
public SmartFragmentStatePagerAdapter(FragmentManager fragmentManager) {
|
||||
super(fragmentManager);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemPosition(Object object) {
|
||||
return POSITION_NONE;
|
||||
}
|
||||
|
||||
// Register the fragment when the item is instantiated
|
||||
@Override
|
||||
public Object instantiateItem(ViewGroup container, int position) {
|
||||
Fragment fragment = (Fragment) super.instantiateItem(container, position);
|
||||
registeredFragments.put(position, fragment);
|
||||
return fragment;
|
||||
}
|
||||
|
||||
// Unregister when the item is inactive
|
||||
@Override
|
||||
public void destroyItem(ViewGroup container, int position, Object object) {
|
||||
registeredFragments.remove(position);
|
||||
super.destroyItem(container, position, object);
|
||||
}
|
||||
|
||||
// Returns the fragment for the position (if instantiated)
|
||||
public Fragment getRegisteredFragment(int position) {
|
||||
return registeredFragments.get(position);
|
||||
}
|
||||
}
|
@@ -0,0 +1,161 @@
|
||||
package com.wismna.geoffroy.donext.adapters;
|
||||
|
||||
import android.support.v4.view.MotionEventCompat;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.wismna.geoffroy.donext.R;
|
||||
import com.wismna.geoffroy.donext.dao.TaskList;
|
||||
import com.wismna.geoffroy.donext.helpers.TaskListTouchHelper;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* {@link RecyclerView.Adapter} that can display a {@link TaskList}.
|
||||
*/
|
||||
|
||||
public class TaskListRecyclerViewAdapter extends RecyclerView.Adapter<TaskListRecyclerViewAdapter.ViewHolder>
|
||||
implements TaskListTouchHelper.TaskListTouchHelperAdapter {
|
||||
|
||||
public interface TaskListRecyclerViewAdapterListener {
|
||||
void onEditTextLoseFocus(TaskList taskList);
|
||||
void onClickDeleteButton(int position, long id);
|
||||
void onItemMove(long fromTaskId, long toTaskId, int fromPosition, int toPosition);
|
||||
void onStartDrag(RecyclerView.ViewHolder viewHolder);
|
||||
}
|
||||
|
||||
private final List<TaskList> mValues;
|
||||
private final TaskListRecyclerViewAdapterListener mListener;
|
||||
|
||||
public TaskListRecyclerViewAdapter(List<TaskList> items,
|
||||
TaskListRecyclerViewAdapterListener listener) {
|
||||
mValues = items;
|
||||
mListener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
View view = LayoutInflater.from(parent.getContext())
|
||||
.inflate(R.layout.fragment_tasklist, parent, false);
|
||||
return new ViewHolder(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(final ViewHolder holder, int position) {
|
||||
holder.mItem = mValues.get(position);
|
||||
holder.mTaskCountView.setText(String.valueOf(mValues.get(position).getTaskCount()));
|
||||
holder.mTaskNameView.setText(mValues.get(position).getName());
|
||||
|
||||
|
||||
holder.handleView.setOnTouchListener(new View.OnTouchListener() {
|
||||
@Override
|
||||
public boolean onTouch(View v, MotionEvent event) {
|
||||
if (MotionEventCompat.getActionMasked(event) ==
|
||||
MotionEvent.ACTION_DOWN) {
|
||||
mListener.onStartDrag(holder);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
// Handle inline name change
|
||||
holder.mTaskNameView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
|
||||
@Override
|
||||
public void onFocusChange(View v, boolean hasFocus) {
|
||||
EditText editText = (EditText) v;
|
||||
String name = editText.getText().toString();
|
||||
|
||||
if (!hasFocus && !holder.mItem.getName().matches(name)) {
|
||||
holder.mItem.setName(name);
|
||||
|
||||
update(holder.mItem, holder.getAdapterPosition());
|
||||
mListener.onEditTextLoseFocus(holder.mItem);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Handle click on delete button
|
||||
holder.mTaskDeleteButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
// Disable the OnFocusChanged listener as it is now pointless and harmful
|
||||
holder.mTaskNameView.setOnFocusChangeListener(null);
|
||||
|
||||
//remove(position);
|
||||
mListener.onClickDeleteButton(holder.getAdapterPosition(), holder.mItem.getId());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return mValues.size();
|
||||
}
|
||||
|
||||
public void add(TaskList item, int position) {
|
||||
mValues.add(position, item);
|
||||
notifyItemInserted(position);
|
||||
}
|
||||
|
||||
public void remove(int position) {
|
||||
mValues.remove(position);
|
||||
notifyItemRemoved(position);
|
||||
}
|
||||
|
||||
private void update(TaskList item, int position) {
|
||||
mValues.set(position, item);
|
||||
notifyItemChanged(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onItemMove(int fromPosition, int toPosition) {
|
||||
long fromTaskId = mValues.get(fromPosition).getId();
|
||||
long toTaskId = mValues.get(toPosition).getId();
|
||||
|
||||
if (fromPosition < toPosition) {
|
||||
for (int i = fromPosition; i < toPosition; i++) {
|
||||
|
||||
Collections.swap(mValues, i, i + 1);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (int i = fromPosition; i > toPosition; i--) {
|
||||
Collections.swap(mValues, i, i - 1);
|
||||
}
|
||||
}
|
||||
mListener.onItemMove(fromTaskId, toTaskId, fromPosition, toPosition);
|
||||
notifyItemMoved(fromPosition, toPosition);
|
||||
return true;
|
||||
}
|
||||
|
||||
class ViewHolder extends RecyclerView.ViewHolder {
|
||||
final View mView;
|
||||
final ImageView handleView;
|
||||
final TextView mTaskCountView;
|
||||
final TextView mTaskNameView;
|
||||
final Button mTaskDeleteButton;
|
||||
TaskList mItem;
|
||||
|
||||
ViewHolder(View view) {
|
||||
super(view);
|
||||
mView = view;
|
||||
handleView = (ImageView) itemView.findViewById(R.id.handle);
|
||||
mTaskCountView = (TextView) view.findViewById(R.id.task_list_count);
|
||||
mTaskNameView = (TextView) view.findViewById(R.id.task_list_name);
|
||||
mTaskDeleteButton = (Button) view.findViewById(R.id.task_list_delete);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.toString() + " '" + mTaskNameView.getText() + "'";
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,174 @@
|
||||
package com.wismna.geoffroy.donext.adapters;
|
||||
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Typeface;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.wismna.geoffroy.donext.R;
|
||||
import com.wismna.geoffroy.donext.dao.Task;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* {@link RecyclerView.Adapter} that can display a {@link Task}.
|
||||
*/
|
||||
public class TaskRecyclerViewAdapter extends RecyclerView.Adapter<TaskRecyclerViewAdapter.SimpleViewHolder> {
|
||||
|
||||
private List<Task> mValues;
|
||||
private int viewType;
|
||||
private boolean mIsToday;
|
||||
|
||||
public TaskRecyclerViewAdapter(List<Task> items, int viewType, boolean isToday) {
|
||||
mValues = items;
|
||||
mIsToday = isToday;
|
||||
this.viewType = viewType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SimpleViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
View view;
|
||||
switch (viewType)
|
||||
{
|
||||
case 1:
|
||||
view = LayoutInflater.from(parent.getContext())
|
||||
.inflate(R.layout.fragment_task_simple, parent, false);
|
||||
return new SimpleViewHolder(view);
|
||||
case 2:
|
||||
view = LayoutInflater.from(parent.getContext())
|
||||
.inflate(R.layout.fragment_task_detailed, parent, false);
|
||||
return new DetailedViewHolder(view);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(final SimpleViewHolder holder, int position) {
|
||||
// Set basic information
|
||||
holder.mItem = mValues.get(position);
|
||||
holder.mIdView.setText(String.valueOf(holder.mItem.getId()));
|
||||
holder.mCycleView.setText(String.valueOf(holder.mItem.getCycle()));
|
||||
holder.mTitleView.setText(holder.mItem.getName());
|
||||
// Set optional description
|
||||
if (holder instanceof DetailedViewHolder)
|
||||
((DetailedViewHolder)holder).mDescriptionView.setText(holder.mItem.getDescription());
|
||||
// Set task rendering
|
||||
holder.mTitleView.setTypeface(Typeface.DEFAULT);
|
||||
holder.mTitleView.setTextColor(Color.BLACK);
|
||||
|
||||
// Additional information will not be displayed in Today view
|
||||
if (mIsToday) return;
|
||||
// Set alarm if past due date
|
||||
LocalDate dueDate = holder.mItem.getDueDate();
|
||||
if(dueDate != null && dueDate.isBefore(LocalDate.now()))
|
||||
holder.mAlarmView.setImageResource(R.drawable.ic_access_alarm);
|
||||
int priority = holder.mItem.getPriority();
|
||||
|
||||
// Set priority
|
||||
switch (priority)
|
||||
{
|
||||
case 0:
|
||||
holder.mTitleView.setTextColor(Color.LTGRAY);
|
||||
break;
|
||||
case 2:
|
||||
holder.mTitleView.setTypeface(holder.mTitleView.getTypeface(), Typeface.BOLD);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return mValues.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
return getItem(position).getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemViewType(int position) {
|
||||
return viewType;
|
||||
}
|
||||
|
||||
public void setItemViewType(int viewType) {
|
||||
this.viewType = viewType;
|
||||
}
|
||||
|
||||
public void add(Task item, int position) {
|
||||
mValues.add(position, item);
|
||||
notifyItemInserted(position);
|
||||
}
|
||||
|
||||
public void remove(int position) {
|
||||
mValues.remove(position);
|
||||
notifyItemRemoved(position);
|
||||
}
|
||||
|
||||
public void update(Task item, int position) {
|
||||
mValues.set(position, item);
|
||||
notifyItemChanged(position);
|
||||
}
|
||||
|
||||
public int getCycleCount() {
|
||||
int count = 0;
|
||||
for (Task task: mValues) {
|
||||
count += task.getCycle();
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
public void setItems(List<Task> tasks) {
|
||||
this.mValues = tasks;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
public Task getItem(int position) {
|
||||
return mValues.get(position);
|
||||
}
|
||||
|
||||
class SimpleViewHolder extends RecyclerView.ViewHolder {
|
||||
final View mView;
|
||||
final TextView mIdView;
|
||||
final ImageView mAlarmView;
|
||||
final TextView mCycleView;
|
||||
final TextView mTitleView;
|
||||
Task mItem;
|
||||
|
||||
SimpleViewHolder(View view) {
|
||||
super(view);
|
||||
mView = view;
|
||||
|
||||
mIdView = (TextView) view.findViewById(R.id.task_id);
|
||||
mAlarmView = (ImageView) view.findViewById(R.id.task_alarm);
|
||||
mCycleView = (TextView) view.findViewById(R.id.task_cycle);
|
||||
mTitleView = (TextView) view.findViewById(R.id.task_name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.toString() + " '" + mTitleView.getText() + "'";
|
||||
}
|
||||
}
|
||||
|
||||
private class DetailedViewHolder extends SimpleViewHolder {
|
||||
private final TextView mDescriptionView;
|
||||
|
||||
private DetailedViewHolder(View view) {
|
||||
super(view);
|
||||
mDescriptionView = (TextView) view.findViewById(R.id.task_description);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.toString() + " '" + mTitleView.getText() + "'";
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,54 @@
|
||||
package com.wismna.geoffroy.donext.adapters;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Typeface;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.wismna.geoffroy.donext.R;
|
||||
import com.wismna.geoffroy.donext.dao.Task;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by bg45 on 2017-03-22.
|
||||
* Custom array adapter for the Today Task list view
|
||||
*/
|
||||
|
||||
public class TodayArrayAdapter extends ArrayAdapter<Task> {
|
||||
public TodayArrayAdapter(@NonNull Context context, @NonNull List<Task> objects) {
|
||||
super(context, R.layout.list_task_item, objects);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
|
||||
//return super.getView(position, convertView, parent);
|
||||
if (convertView == null) {
|
||||
convertView = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_task_item, parent, false);
|
||||
}
|
||||
TextView titleView = (TextView) convertView.findViewById(R.id.task_list_item_title);
|
||||
TextView taskView = (TextView) convertView.findViewById(R.id.task_list_item_tasklist);
|
||||
LinearLayout layoutView = (LinearLayout) convertView.findViewById(R.id.task_list_item_layout);
|
||||
Task item = this.getItem(position);
|
||||
if (item != null) {
|
||||
titleView.setText(item.getName());
|
||||
taskView.setText(item.getTaskListName());
|
||||
if (item.isToday()) {
|
||||
titleView.setTypeface(titleView.getTypeface(), Typeface.BOLD);
|
||||
layoutView.setBackgroundColor(Color.parseColor("#B2DFDB"));
|
||||
} else {
|
||||
titleView.setTypeface(Typeface.DEFAULT);
|
||||
layoutView.setBackgroundColor(Color.WHITE);
|
||||
}
|
||||
}
|
||||
return convertView;
|
||||
}
|
||||
}
|
125
app/src/main/java/com/wismna/geoffroy/donext/dao/Task.java
Normal file
@@ -0,0 +1,125 @@
|
||||
package com.wismna.geoffroy.donext.dao;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
|
||||
/**
|
||||
* Created by geoffroy on 15-11-25.
|
||||
* Data access object class that represents a Task
|
||||
*/
|
||||
public class Task {
|
||||
private long id;
|
||||
private String name;
|
||||
private String description;
|
||||
private int priority;
|
||||
private int cycle;
|
||||
private int done;
|
||||
private int deleted;
|
||||
private long taskList;
|
||||
private String taskListName;
|
||||
private LocalDate dueDate;
|
||||
private LocalDate todayDate;
|
||||
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String comment) {
|
||||
this.name = comment;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public int getPriority() {
|
||||
return priority;
|
||||
}
|
||||
|
||||
public void setPriority(int priority) {
|
||||
this.priority = priority;
|
||||
}
|
||||
|
||||
public int getCycle() {
|
||||
return cycle;
|
||||
}
|
||||
|
||||
public void setCycle(int cycle) {
|
||||
this.cycle = cycle;
|
||||
}
|
||||
|
||||
public boolean isDone() {
|
||||
return done != 0;
|
||||
}
|
||||
|
||||
public void setDone(int done) {
|
||||
this.done = done;
|
||||
}
|
||||
|
||||
public boolean isDeleted() {
|
||||
return deleted != 0;
|
||||
}
|
||||
|
||||
public void setDeleted(int deleted) {
|
||||
this.deleted = deleted;
|
||||
}
|
||||
|
||||
public long getTaskListId() {
|
||||
return taskList;
|
||||
}
|
||||
|
||||
public void setTaskList(long taskList) {
|
||||
this.taskList = taskList;
|
||||
}
|
||||
|
||||
public String getTaskListName() {
|
||||
return taskListName;
|
||||
}
|
||||
|
||||
public void setTaskListName(String taskListName) {
|
||||
this.taskListName = taskListName;
|
||||
}
|
||||
|
||||
public void setDueDate(String dueDate) {
|
||||
try {
|
||||
this.dueDate = LocalDate.parse(dueDate);
|
||||
}
|
||||
catch (Exception e){
|
||||
this.dueDate = null;
|
||||
}
|
||||
}
|
||||
|
||||
public LocalDate getDueDate() {
|
||||
return dueDate;
|
||||
}
|
||||
|
||||
public void setTodayDate(String todayDate) {
|
||||
try {
|
||||
this.todayDate = LocalDate.parse(todayDate);
|
||||
}
|
||||
catch (Exception e){
|
||||
this.todayDate = null;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isToday() {
|
||||
return todayDate != null && todayDate.isEqual(LocalDate.now());
|
||||
}
|
||||
|
||||
// Will be used by the ArrayAdapter in the ListView
|
||||
@Override
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
}
|
@@ -0,0 +1,57 @@
|
||||
package com.wismna.geoffroy.donext.dao;
|
||||
|
||||
/**
|
||||
* Created by geoffroy on 15-11-25.
|
||||
* Data access object class that represents a Task List
|
||||
*/
|
||||
public class TaskList {
|
||||
private long id;
|
||||
private String name;
|
||||
private long taskCount;
|
||||
private int order;
|
||||
private Boolean visible;
|
||||
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String comment) {
|
||||
this.name = comment;
|
||||
}
|
||||
|
||||
public long getTaskCount() {
|
||||
return taskCount;
|
||||
}
|
||||
|
||||
public void setTaskCount(long taskCount) {
|
||||
this.taskCount = taskCount;
|
||||
}
|
||||
|
||||
public int getOrder() {
|
||||
return order;
|
||||
}
|
||||
|
||||
public void setOrder(int order) {
|
||||
this.order = order;
|
||||
}
|
||||
|
||||
public void setVisible(int visible) {
|
||||
this.visible = visible != 0;
|
||||
}
|
||||
public Boolean isVisible() {
|
||||
return visible;
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,93 @@
|
||||
package com.wismna.geoffroy.donext.database;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.database.sqlite.SQLiteOpenHelper;
|
||||
|
||||
/**
|
||||
* Created by geoffroy on 15-11-25.
|
||||
* Database helper class that contains table and column names as well as handles database creation
|
||||
*/
|
||||
class DatabaseHelper extends SQLiteOpenHelper {
|
||||
private static final int DATABASE_VERSION = 5;
|
||||
private static final String DATABASE_NAME = "donext.db";
|
||||
static final String COLUMN_ID = "_id";
|
||||
static final String COLUMN_ORDER = "displayorder";
|
||||
|
||||
static final String TASKLIST_TABLE_NAME = "tasklist";
|
||||
static final String TASKLIST_COLUMN_NAME = "name";
|
||||
static final String TASKLIST_COLUMN_TASK_COUNT = "taskcount";
|
||||
static final String TASKLIST_COLUMN_VISIBLE = "visible";
|
||||
private static final String TASKLIST_TABLE_CREATE =
|
||||
"CREATE TABLE " + TASKLIST_TABLE_NAME + " (" +
|
||||
COLUMN_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
|
||||
TASKLIST_COLUMN_NAME + " TEXT NOT NULL, " +
|
||||
COLUMN_ORDER + " INTEGER, " +
|
||||
TASKLIST_COLUMN_VISIBLE + " INTEGER DEFAULT 1" +
|
||||
");";
|
||||
|
||||
static final String TASKS_TABLE_NAME = "tasks";
|
||||
static final String TASKS_COLUMN_NAME = "name";
|
||||
static final String TASKS_COLUMN_DESC = "description";
|
||||
static final String TASKS_COLUMN_CYCLE = "cycle";
|
||||
static final String TASKS_COLUMN_PRIORITY = "priority";
|
||||
static final String TASKS_COLUMN_DONE = "done";
|
||||
static final String TASKS_COLUMN_DELETED= "deleted";
|
||||
static final String TASKS_COLUMN_LIST = "list";
|
||||
static final String TASKS_COLUMN_DUEDATE = "duedate";
|
||||
static final String TASKS_COLUMN_TODAYDATE = "todaydate";
|
||||
private static final String TASKS_TABLE_CREATE =
|
||||
"CREATE TABLE " + TASKS_TABLE_NAME + " (" +
|
||||
COLUMN_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
|
||||
TASKS_COLUMN_NAME + " TEXT NOT NULL, " +
|
||||
TASKS_COLUMN_DESC + " TEXT, " +
|
||||
TASKS_COLUMN_PRIORITY + " INTEGER, " +
|
||||
TASKS_COLUMN_CYCLE + " INTEGER DEFAULT 0, " +
|
||||
TASKS_COLUMN_DONE + " INTEGER DEFAULT 0, " +
|
||||
TASKS_COLUMN_DELETED + " INTEGER DEFAULT 0, " +
|
||||
COLUMN_ORDER + " INTEGER, " +
|
||||
TASKS_COLUMN_LIST + " INTEGER NOT NULL " +
|
||||
"REFERENCES " + TASKLIST_TABLE_NAME + "(" + COLUMN_ID + "), " +
|
||||
TASKS_COLUMN_DUEDATE + " DATE, " +
|
||||
TASKS_COLUMN_TODAYDATE + " DATE" +
|
||||
");";
|
||||
|
||||
static final String TASKS_VIEW_TODAY_NAME = "today";
|
||||
private static final String TASKS_VIEW_TODAY_CREATE =
|
||||
"CREATE VIEW " + TASKS_VIEW_TODAY_NAME + " AS" +
|
||||
" SELECT * FROM " + TASKS_TABLE_NAME +
|
||||
" WHERE " + TASKS_COLUMN_TODAYDATE + " = date('now','localtime')";
|
||||
DatabaseHelper(Context context) {
|
||||
super(context, DATABASE_NAME, null, DATABASE_VERSION);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(SQLiteDatabase db) {
|
||||
db.execSQL(TASKLIST_TABLE_CREATE);
|
||||
db.execSQL(TASKS_TABLE_CREATE);
|
||||
db.execSQL(TASKS_VIEW_TODAY_CREATE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
||||
// Fall-through is intended
|
||||
switch (oldVersion) {
|
||||
case 1:
|
||||
// Add new Order column
|
||||
db.execSQL("ALTER TABLE " + TASKLIST_TABLE_NAME + " ADD COLUMN " + COLUMN_ORDER + " INTEGER");
|
||||
case 2:
|
||||
// Add new Visible column
|
||||
db.execSQL("ALTER TABLE " + TASKLIST_TABLE_NAME + " ADD COLUMN " + TASKLIST_COLUMN_VISIBLE + " INTEGER DEFAULT 1");
|
||||
// Add new Due Date column
|
||||
db.execSQL("ALTER TABLE " + TASKS_TABLE_NAME + " ADD COLUMN " + TASKS_COLUMN_DUEDATE + " DATE");
|
||||
case 3:
|
||||
// Add new Today Date column
|
||||
db.execSQL("ALTER TABLE " + TASKS_TABLE_NAME + " ADD COLUMN " + TASKS_COLUMN_TODAYDATE + " DATE");
|
||||
// Create the Today view
|
||||
db.execSQL(TASKS_VIEW_TODAY_CREATE);
|
||||
case 4:
|
||||
db.execSQL("DROP VIEW " + TASKS_VIEW_TODAY_NAME);
|
||||
db.execSQL(TASKS_VIEW_TODAY_CREATE);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,185 @@
|
||||
package com.wismna.geoffroy.donext.database;
|
||||
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.database.SQLException;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
|
||||
import com.wismna.geoffroy.donext.dao.Task;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by geoffroy on 15-11-27.
|
||||
* Data access class that handles Tasks
|
||||
*/
|
||||
public class TaskDataAccess implements AutoCloseable {
|
||||
public enum MODE {
|
||||
READ,
|
||||
WRITE
|
||||
}
|
||||
|
||||
private SQLiteDatabase database;
|
||||
private final DatabaseHelper dbHelper;
|
||||
private final String[] taskColumns = {
|
||||
DatabaseHelper.COLUMN_ID, DatabaseHelper.TASKS_COLUMN_NAME,
|
||||
DatabaseHelper.TASKS_COLUMN_DESC, DatabaseHelper.TASKS_COLUMN_PRIORITY,
|
||||
DatabaseHelper.TASKS_COLUMN_CYCLE, DatabaseHelper.TASKS_COLUMN_DONE,
|
||||
DatabaseHelper.TASKS_COLUMN_DELETED, DatabaseHelper.TASKS_COLUMN_LIST,
|
||||
DatabaseHelper.TASKS_COLUMN_DUEDATE, DatabaseHelper.TASKS_COLUMN_TODAYDATE};
|
||||
|
||||
public TaskDataAccess(Context context) {
|
||||
this(context, MODE.READ);
|
||||
}
|
||||
public TaskDataAccess(Context context, MODE writeMode) {
|
||||
dbHelper = new DatabaseHelper(context);
|
||||
open(writeMode);
|
||||
}
|
||||
|
||||
private void open(MODE writeMode) throws SQLException {
|
||||
if (writeMode == MODE.WRITE) database = dbHelper.getWritableDatabase();
|
||||
else database = dbHelper.getReadableDatabase();
|
||||
}
|
||||
|
||||
public void close() {
|
||||
dbHelper.close();
|
||||
}
|
||||
|
||||
/** Adds or update a task in the database */
|
||||
public Task createOrUpdateTask(long id, String name, String description, int priority,
|
||||
long taskList, String dueDate, boolean isTodayList) {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(DatabaseHelper.TASKS_COLUMN_NAME, name);
|
||||
values.put(DatabaseHelper.TASKS_COLUMN_DESC, description);
|
||||
values.put(DatabaseHelper.TASKS_COLUMN_PRIORITY, priority);
|
||||
values.put(DatabaseHelper.TASKS_COLUMN_LIST, taskList);
|
||||
values.put(DatabaseHelper.TASKS_COLUMN_DUEDATE, dueDate);
|
||||
values.put(DatabaseHelper.TASKS_COLUMN_TODAYDATE, isTodayList? LocalDate.now().toString() : "");
|
||||
long insertId;
|
||||
if (id == 0)
|
||||
insertId = database.insert(DatabaseHelper.TASKS_TABLE_NAME, null, values);
|
||||
else {
|
||||
database.update(DatabaseHelper.TASKS_TABLE_NAME, values, DatabaseHelper.COLUMN_ID + " == " + id, null);
|
||||
insertId = id;
|
||||
}
|
||||
Cursor cursor = database.query(DatabaseHelper.TASKS_TABLE_NAME,
|
||||
taskColumns, DatabaseHelper.COLUMN_ID + " = " + insertId, null,
|
||||
null, null, null);
|
||||
cursor.moveToFirst();
|
||||
Task newTask = cursorToTask(cursor);
|
||||
cursor.close();
|
||||
return newTask;
|
||||
}
|
||||
|
||||
public void updateTodayTasks(long id, boolean isTodayList){
|
||||
ContentValues contentValues = new ContentValues();
|
||||
contentValues.put(DatabaseHelper.TASKS_COLUMN_TODAYDATE, isTodayList? LocalDate.now().toString() : "");
|
||||
database.update(DatabaseHelper.TASKS_TABLE_NAME, contentValues,
|
||||
DatabaseHelper.COLUMN_ID + " == " + id, null);
|
||||
}
|
||||
|
||||
public List<Task> getAllTasks() {
|
||||
Cursor cursor = database.rawQuery("SELECT " +
|
||||
DatabaseHelper.TASKS_TABLE_NAME + "." + DatabaseHelper.COLUMN_ID + "," +
|
||||
DatabaseHelper.TASKS_TABLE_NAME + "." + DatabaseHelper.TASKS_COLUMN_NAME + "," +
|
||||
DatabaseHelper.TASKS_TABLE_NAME + "." + DatabaseHelper.TASKS_COLUMN_TODAYDATE + "," +
|
||||
DatabaseHelper.TASKLIST_TABLE_NAME + "." + DatabaseHelper.TASKLIST_COLUMN_NAME + " AS tasklistname " +
|
||||
" FROM " + DatabaseHelper.TASKS_TABLE_NAME +
|
||||
" LEFT JOIN " + DatabaseHelper.TASKLIST_TABLE_NAME +
|
||||
" ON " + DatabaseHelper.TASKS_TABLE_NAME + "." + DatabaseHelper.TASKS_COLUMN_LIST +
|
||||
" = " + DatabaseHelper.TASKLIST_TABLE_NAME + "." + DatabaseHelper.COLUMN_ID +
|
||||
" WHERE " + DatabaseHelper.TASKS_TABLE_NAME + "." + DatabaseHelper.TASKS_COLUMN_DONE + " = " + 0 +
|
||||
" AND " + DatabaseHelper.TASKS_TABLE_NAME + "." + DatabaseHelper.TASKS_COLUMN_DELETED + " = " + 0
|
||||
, null);
|
||||
List<Task> tasks = new ArrayList<>();
|
||||
|
||||
cursor.moveToFirst();
|
||||
while (!cursor.isAfterLast()) {
|
||||
Task task = new Task();
|
||||
task.setId(cursor.getLong(0));
|
||||
task.setName(cursor.getString(1));
|
||||
task.setTodayDate(cursor.getString(2));
|
||||
task.setTaskListName(cursor.getString(3));
|
||||
tasks.add(task);
|
||||
cursor.moveToNext();
|
||||
}
|
||||
// make sure to close the cursor
|
||||
cursor.close();
|
||||
|
||||
return tasks;
|
||||
}
|
||||
|
||||
public List<Task> getAllTasksFromList(long id, boolean isHistory) {
|
||||
int history = isHistory ? 1 : 0;
|
||||
Cursor cursor = database.query(DatabaseHelper.TASKS_TABLE_NAME, taskColumns,
|
||||
DatabaseHelper.TASKS_COLUMN_LIST + " = " + id +
|
||||
" AND (" + DatabaseHelper.TASKS_COLUMN_DONE + " = " + history +
|
||||
(isHistory ? " OR " : " AND ") + DatabaseHelper.TASKS_COLUMN_DELETED + " = " + history + ")",
|
||||
null, null, null,
|
||||
DatabaseHelper.TASKS_COLUMN_CYCLE + ", " + DatabaseHelper.COLUMN_ID + " DESC");
|
||||
return getTasksFromCursor(cursor);
|
||||
}
|
||||
|
||||
public List<Task> getTodayTasks() {
|
||||
Cursor cursor = database.query(DatabaseHelper.TASKS_VIEW_TODAY_NAME, taskColumns,
|
||||
DatabaseHelper.TASKS_COLUMN_DONE + " = " + 0 +
|
||||
" AND " + DatabaseHelper.TASKS_COLUMN_DELETED + " = " + 0,
|
||||
null, null, null,
|
||||
DatabaseHelper.TASKS_COLUMN_CYCLE + ", " + DatabaseHelper.COLUMN_ID + " DESC");
|
||||
return getTasksFromCursor(cursor);
|
||||
}
|
||||
|
||||
public int setDone(long id) {
|
||||
return update(id, DatabaseHelper.TASKS_COLUMN_DONE, 1);
|
||||
}
|
||||
|
||||
public int increaseCycle(int newCycle, long id) {
|
||||
return update(id, DatabaseHelper.TASKS_COLUMN_CYCLE, newCycle);
|
||||
}
|
||||
|
||||
public int deleteTask(long id) {
|
||||
/*database.delete(DatabaseHelper.TASKS_TABLE_NAME,
|
||||
DatabaseHelper.COLUMN_ID + " = " + taskId, null);*/
|
||||
return update(id, DatabaseHelper.TASKS_COLUMN_DELETED, 1);
|
||||
}
|
||||
|
||||
private int update(long id, String column, Object value) {
|
||||
ContentValues contentValues = new ContentValues();
|
||||
if (value instanceof Integer)
|
||||
contentValues.put(column, (int) value);
|
||||
return database.update(DatabaseHelper.TASKS_TABLE_NAME, contentValues, DatabaseHelper.COLUMN_ID + " = " + id, null);
|
||||
}
|
||||
|
||||
private Task cursorToTask(Cursor cursor) {
|
||||
Task task = new Task();
|
||||
task.setId(cursor.getLong(0));
|
||||
task.setName(cursor.getString(1));
|
||||
task.setDescription(cursor.getString(2));
|
||||
task.setPriority(cursor.getInt(3));
|
||||
task.setCycle(cursor.getInt(4));
|
||||
task.setDone(cursor.getInt(5));
|
||||
task.setDeleted(cursor.getInt(6));
|
||||
task.setTaskList(cursor.getLong(7));
|
||||
task.setDueDate(cursor.getString(8));
|
||||
task.setTodayDate(cursor.getString(9));
|
||||
return task;
|
||||
}
|
||||
|
||||
private List<Task> getTasksFromCursor(Cursor cursor) {
|
||||
List<Task> tasks = new ArrayList<>();
|
||||
|
||||
cursor.moveToFirst();
|
||||
while (!cursor.isAfterLast()) {
|
||||
Task task = cursorToTask(cursor);
|
||||
tasks.add(task);
|
||||
cursor.moveToNext();
|
||||
}
|
||||
// make sure to close the cursor
|
||||
cursor.close();
|
||||
return tasks;
|
||||
}
|
||||
}
|
@@ -0,0 +1,144 @@
|
||||
package com.wismna.geoffroy.donext.database;
|
||||
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.database.SQLException;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
|
||||
import com.wismna.geoffroy.donext.dao.TaskList;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by geoffroy on 15-11-25.
|
||||
* Data access class that handles Task Lists
|
||||
*/
|
||||
public class TaskListDataAccess implements AutoCloseable {
|
||||
public enum MODE {
|
||||
READ,
|
||||
WRITE
|
||||
}
|
||||
// Database fields
|
||||
private SQLiteDatabase database;
|
||||
private final DatabaseHelper dbHelper;
|
||||
private final String[] taskListColumns =
|
||||
{DatabaseHelper.COLUMN_ID, DatabaseHelper.TASKLIST_COLUMN_NAME,
|
||||
DatabaseHelper.COLUMN_ORDER, DatabaseHelper.TASKLIST_COLUMN_VISIBLE};
|
||||
|
||||
public TaskListDataAccess(Context context) {
|
||||
this(context, MODE.READ);
|
||||
}
|
||||
public TaskListDataAccess(Context context, MODE writeMode) {
|
||||
dbHelper = new DatabaseHelper(context);
|
||||
open(writeMode);
|
||||
}
|
||||
|
||||
public void open(MODE writeMode) throws SQLException {
|
||||
if (writeMode == MODE.WRITE) database = dbHelper.getWritableDatabase();
|
||||
else database = dbHelper.getReadableDatabase();
|
||||
}
|
||||
|
||||
public void close() {
|
||||
dbHelper.close();
|
||||
}
|
||||
|
||||
public TaskList createTaskList(String name, int order) {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(DatabaseHelper.TASKLIST_COLUMN_NAME, name);
|
||||
values.put(DatabaseHelper.COLUMN_ORDER, order);
|
||||
values.put(DatabaseHelper.TASKLIST_COLUMN_VISIBLE, 1);
|
||||
long insertId = database.insert(DatabaseHelper.TASKLIST_TABLE_NAME, null,
|
||||
values);
|
||||
Cursor cursor = database.query(DatabaseHelper.TASKLIST_TABLE_NAME,
|
||||
taskListColumns, DatabaseHelper.COLUMN_ID + " = " + insertId, null,
|
||||
null, null, null);
|
||||
cursor.moveToFirst();
|
||||
TaskList newTaskList = cursorToTaskList(cursor);
|
||||
cursor.close();
|
||||
return newTaskList;
|
||||
}
|
||||
|
||||
public void deleteTaskList(long id) {
|
||||
// Delete all related tasks
|
||||
database.delete(DatabaseHelper.TASKS_TABLE_NAME, DatabaseHelper.TASKS_COLUMN_LIST
|
||||
+ " = " + id, null);
|
||||
// Delete list
|
||||
database.delete(DatabaseHelper.TASKLIST_TABLE_NAME, DatabaseHelper.COLUMN_ID
|
||||
+ " = " + id, null);
|
||||
}
|
||||
|
||||
public void updateOrder(long id, int order) {
|
||||
update(id, DatabaseHelper.COLUMN_ORDER, order);
|
||||
}
|
||||
|
||||
public void updateName(long id, String name) {
|
||||
update(id, DatabaseHelper.TASKLIST_COLUMN_NAME, name);
|
||||
}
|
||||
|
||||
public TaskList getTaskListByName(String name) {
|
||||
Cursor cursor = getTaskListByNameCursor(name);
|
||||
TaskList taskList = null;
|
||||
if (cursor.getCount() > 0) {
|
||||
cursor.moveToFirst();
|
||||
taskList = cursorToTaskList(cursor);
|
||||
cursor.close();
|
||||
}
|
||||
return taskList;
|
||||
}
|
||||
|
||||
public List<TaskList> getAllTaskLists() {
|
||||
List<TaskList> taskLists = new ArrayList<>();
|
||||
|
||||
Cursor cursor = getAllTaskListsCursor();
|
||||
cursor.moveToFirst();
|
||||
while (!cursor.isAfterLast()) {
|
||||
TaskList taskList = cursorToTaskList(cursor);
|
||||
taskLists.add(taskList);
|
||||
cursor.moveToNext();
|
||||
}
|
||||
// make sure to close the cursor
|
||||
cursor.close();
|
||||
return taskLists;
|
||||
}
|
||||
|
||||
private void update(long id, String column, Object value)
|
||||
{
|
||||
ContentValues contentValues = new ContentValues();
|
||||
if (value instanceof String)
|
||||
contentValues.put(column, (String) value);
|
||||
if (value instanceof Integer)
|
||||
contentValues.put(column, (int) value);
|
||||
database.update(DatabaseHelper.TASKLIST_TABLE_NAME, contentValues, DatabaseHelper.COLUMN_ID + " = " + id, null);
|
||||
}
|
||||
|
||||
private Cursor getTaskListByNameCursor(String name) {
|
||||
return database.query(true, DatabaseHelper.TASKLIST_TABLE_NAME, taskListColumns,
|
||||
DatabaseHelper.TASKLIST_COLUMN_NAME + " = '" + name.replace("'", "''") + "'", null, null, null, null, null);
|
||||
}
|
||||
private Cursor getAllTaskListsCursor() {
|
||||
return database.rawQuery("SELECT *," +
|
||||
" (SELECT COUNT(*) " +
|
||||
" FROM " + DatabaseHelper.TASKS_TABLE_NAME +
|
||||
" WHERE " + DatabaseHelper.TASKS_TABLE_NAME + "." + DatabaseHelper.TASKS_COLUMN_LIST + " = " +
|
||||
DatabaseHelper.TASKLIST_TABLE_NAME + "." + DatabaseHelper.COLUMN_ID + ") AS " + DatabaseHelper.TASKLIST_COLUMN_TASK_COUNT +
|
||||
" FROM " + DatabaseHelper.TASKLIST_TABLE_NAME +
|
||||
" WHERE " + DatabaseHelper.TASKLIST_COLUMN_VISIBLE + " = " + 1 +
|
||||
" ORDER BY " + DatabaseHelper.COLUMN_ORDER + " ASC ",
|
||||
null);
|
||||
}
|
||||
|
||||
private TaskList cursorToTaskList(Cursor cursor) {
|
||||
TaskList taskList = new TaskList();
|
||||
taskList.setId(cursor.getLong(0));
|
||||
taskList.setName(cursor.getString(1));
|
||||
taskList.setOrder(cursor.getInt(2));
|
||||
taskList.setVisible(cursor.getInt(3));
|
||||
// Get "false" count column if it exists
|
||||
if (cursor.getColumnCount() == 5)
|
||||
taskList.setTaskCount(cursor.getLong(4));
|
||||
return taskList;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,87 @@
|
||||
package com.wismna.geoffroy.donext.fragments;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Dialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
|
||||
import com.wismna.geoffroy.donext.R;
|
||||
|
||||
public class ConfirmDialogFragment extends DialogFragment {
|
||||
interface ConfirmDialogListener {
|
||||
void onConfirmDialogClick(DialogFragment dialog, ButtonEvent event);
|
||||
}
|
||||
|
||||
enum ButtonEvent{
|
||||
YES,
|
||||
NO
|
||||
}
|
||||
private ConfirmDialogListener confirmDialogListener;
|
||||
//private String message;
|
||||
|
||||
public static ConfirmDialogFragment newInstance(/*String message, */ConfirmDialogListener confirmDialogListener) {
|
||||
ConfirmDialogFragment fragment = new ConfirmDialogFragment();
|
||||
//fragment.message = message;
|
||||
fragment.confirmDialogListener = confirmDialogListener;
|
||||
fragment.setRetainInstance(true);
|
||||
return fragment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCancel(DialogInterface dialog) {
|
||||
super.onCancel(dialog);
|
||||
|
||||
// Allows refreshing the first item of the adapter
|
||||
confirmDialogListener.onConfirmDialogClick(this, ButtonEvent.NO);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
|
||||
|
||||
Bundle args = getArguments();
|
||||
LayoutInflater inflater = getActivity().getLayoutInflater();
|
||||
// No need for a parent in a Dialog Fragment
|
||||
@SuppressLint("InflateParams") View view = inflater.inflate(R.layout.fragment_task_confirmation, null);
|
||||
builder.setView(view).setMessage(args.getString("message"))
|
||||
.setPositiveButton(args.getInt("button"), new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int id) {
|
||||
confirmDialogListener.onConfirmDialogClick(ConfirmDialogFragment.this, ButtonEvent.YES);
|
||||
}
|
||||
})
|
||||
.setNegativeButton(R.string.task_confirmation_no_button, new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int id) {
|
||||
// User cancelled the dialog
|
||||
ConfirmDialogFragment.this.getDialog().cancel();
|
||||
}
|
||||
})
|
||||
.setOnKeyListener(new DialogInterface.OnKeyListener() {
|
||||
@Override
|
||||
public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
|
||||
return keyCode != KeyEvent.KEYCODE_BACK;
|
||||
}
|
||||
});
|
||||
// Create the AlertDialog object and return it
|
||||
Dialog dialog = builder.create();
|
||||
dialog.setCanceledOnTouchOutside(true);
|
||||
return dialog;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
Dialog dialog = getDialog();
|
||||
// Stop the dialog from being dismissed on rotation, due to a bug with the compatibility library
|
||||
// https://code.google.com/p/android/issues/detail?id=17423
|
||||
if (dialog != null && getRetainInstance()) {
|
||||
dialog.setDismissMessage(null);
|
||||
}
|
||||
super.onDestroyView();
|
||||
}
|
||||
}
|
@@ -0,0 +1,198 @@
|
||||
package com.wismna.geoffroy.donext.fragments;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.Dialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
import android.support.v7.app.ActionBar;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.support.v7.widget.Toolbar;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import com.wismna.geoffroy.donext.R;
|
||||
|
||||
/**
|
||||
* Created by wismna on 2017-03-21.
|
||||
* Sub-class this class to create a dynamic fragment that will act as a Dialog in large layouts and
|
||||
* a full screen fragment in smaller layouts.
|
||||
*/
|
||||
|
||||
public abstract class DynamicDialogFragment extends DialogFragment {
|
||||
int mButtonCount = 2;
|
||||
int mContentLayoutId = 0;
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
// This part is only needed on small layouts (large layouts use onCreateDialog)
|
||||
if (!getShowsDialog()) {
|
||||
View view = inflater.inflate(R.layout.fragment_dynamic_dialog, container, false);
|
||||
AppCompatActivity activity = (AppCompatActivity) getActivity();
|
||||
assert activity != null;
|
||||
activity.setSupportActionBar(setToolbarTitle(view));
|
||||
|
||||
ActionBar actionBar = activity.getSupportActionBar();
|
||||
if (actionBar != null) {
|
||||
actionBar.setDisplayHomeAsUpEnabled(true);
|
||||
actionBar.setHomeButtonEnabled(true);
|
||||
actionBar.setHomeAsUpIndicator(android.R.drawable.ic_menu_close_clear_cancel);
|
||||
}
|
||||
setHasOptionsMenu(true);
|
||||
insertContentView(view, inflater);
|
||||
return view;
|
||||
}
|
||||
// This basically returns null
|
||||
return super.onCreateView(inflater, container, savedInstanceState);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
// Inflate and set the layout for the dialog
|
||||
LayoutInflater inflater = getActivity().getLayoutInflater();
|
||||
// As it is a Dialog, the root ViewGroup can be null without issues
|
||||
@SuppressLint("InflateParams") final View view = inflater.inflate(R.layout.fragment_dynamic_dialog, null);
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
|
||||
Bundle args = getArguments();
|
||||
// Set the dialog buttons
|
||||
assert args != null;
|
||||
// Add action buttons
|
||||
builder.setView(view)
|
||||
.setNegativeButton(args.getString("button_negative"), new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int id) {
|
||||
// Send the negative button event back to the host activity
|
||||
// Canceled creation, nothing to do
|
||||
//dialog.cancel();
|
||||
onNegativeButtonClick();
|
||||
}
|
||||
});
|
||||
if (mButtonCount == 2) {
|
||||
builder.setPositiveButton(args.getString("button_positive"), new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int id) {
|
||||
onPositiveButtonClick(view);
|
||||
}
|
||||
});
|
||||
}
|
||||
if (mButtonCount == 3) {
|
||||
builder.setNeutralButton(args.getString("button_neutral"), new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
onNeutralButtonClick(view);
|
||||
}
|
||||
});
|
||||
}
|
||||
setToolbarTitle(view);
|
||||
insertContentView(view, inflater);
|
||||
return builder.create();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||
//super.onCreateOptionsMenu(menu, inflater);
|
||||
menu.clear();
|
||||
getActivity().getMenuInflater().inflate(R.menu.menu_dynamic_fragment, menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPrepareOptionsMenu(Menu menu) {
|
||||
Bundle args = getArguments();
|
||||
// Show the neutral button if needed
|
||||
if (mButtonCount < 3) {
|
||||
menu.removeItem(R.id.menu_neutral_button);
|
||||
}
|
||||
else {
|
||||
menu.findItem(R.id.menu_neutral_button).setTitle(args.getString("button_neutral"));
|
||||
}
|
||||
|
||||
// Show the positive button if needed
|
||||
if (mButtonCount < 2) {
|
||||
menu.removeItem(R.id.menu_positive_button);
|
||||
}
|
||||
else {
|
||||
menu.findItem(R.id.menu_positive_button).setTitle(args.getString("button_positive"));
|
||||
}
|
||||
super.onPrepareOptionsMenu(menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
// Determine which menu item was clicked
|
||||
int id = item.getItemId();
|
||||
View view = getView();
|
||||
|
||||
// Hide the keyboard if present
|
||||
if (view != null) {
|
||||
InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Activity.INPUT_METHOD_SERVICE);
|
||||
assert imm != null;
|
||||
imm.hideSoftInputFromWindow(getView().getWindowToken(), 0);
|
||||
}
|
||||
if (id == R.id.menu_positive_button) {
|
||||
// Handle positive button click here
|
||||
onPositiveButtonClick(view);
|
||||
return true;
|
||||
}
|
||||
else if (id == R.id.menu_neutral_button) {
|
||||
// Handle neutral button click here
|
||||
onNeutralButtonClick(view);
|
||||
return true;
|
||||
}
|
||||
else if (id == android.R.id.home) {
|
||||
// Handle negative button click here
|
||||
onNegativeButtonClick();
|
||||
return true;
|
||||
}
|
||||
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
Dialog dialog = getDialog();
|
||||
// Stop the dialog from being dismissed on rotation, due to a bug with the compatibility library
|
||||
// https://code.google.com/p/android/issues/detail?id=17423
|
||||
if (dialog != null && getRetainInstance()) {
|
||||
dialog.setDismissMessage(null);
|
||||
}
|
||||
super.onDestroyView();
|
||||
}
|
||||
|
||||
/** Helper function to get a View, without having to worry about the fact that is a Dialog or not*/
|
||||
protected View findViewById(int id) {
|
||||
if (getShowsDialog()) return getDialog().findViewById(id);
|
||||
return getView().findViewById(id);
|
||||
}
|
||||
|
||||
/** Sets the title of the Fragment from the Tag */
|
||||
private Toolbar setToolbarTitle(View view) {
|
||||
Toolbar toolbar = view.findViewById(R.id.dialog_toolbar);
|
||||
toolbar.setTitle(getTag());
|
||||
return toolbar;
|
||||
}
|
||||
|
||||
/** Inserts the actual contents in the content Frame Layout */
|
||||
private void insertContentView(View view, LayoutInflater inflater) {
|
||||
// Ensure that the content view is set
|
||||
if (mContentLayoutId == 0) return;
|
||||
// Insert the content view
|
||||
FrameLayout content = view.findViewById(R.id.dynamic_fragment_content);
|
||||
content.addView(inflater.inflate(mContentLayoutId, (ViewGroup) view.getParent()));
|
||||
}
|
||||
|
||||
protected abstract void onPositiveButtonClick(View view);
|
||||
|
||||
protected abstract void onNeutralButtonClick(View view);
|
||||
|
||||
protected abstract void onNegativeButtonClick();
|
||||
}
|
@@ -0,0 +1,235 @@
|
||||
package com.wismna.geoffroy.donext.fragments;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.graphics.Point;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.design.widget.TabLayout;
|
||||
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.AppCompatActivity;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.support.v7.widget.Toolbar;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.ListView;
|
||||
|
||||
import com.wismna.geoffroy.donext.R;
|
||||
import com.wismna.geoffroy.donext.activities.TaskListActivity;
|
||||
import com.wismna.geoffroy.donext.adapters.SmartFragmentStatePagerAdapter;
|
||||
import com.wismna.geoffroy.donext.adapters.TaskRecyclerViewAdapter;
|
||||
import com.wismna.geoffroy.donext.dao.Task;
|
||||
import com.wismna.geoffroy.donext.dao.TaskList;
|
||||
import com.wismna.geoffroy.donext.database.TaskListDataAccess;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Fragment that will handle the main display
|
||||
*/
|
||||
public class MainFragment extends Fragment implements TasksFragment.TaskChangedAdapter {
|
||||
|
||||
private View mView;
|
||||
private ViewPager mViewPager;
|
||||
private SectionsPagerAdapter mSectionsPagerAdapter;
|
||||
private TabLayout tabLayout;
|
||||
private List<TaskList> taskLists;
|
||||
private boolean isHistory = false;
|
||||
|
||||
public MainFragment() {
|
||||
// Required empty public constructor
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this factory method to create a new instance of
|
||||
* this fragment using the provided parameters.
|
||||
*
|
||||
* @param isHistory Will this fragment show the task history?
|
||||
* @return A new instance of fragment MainFragment.
|
||||
*/
|
||||
// TODO: Rename and change types and number of parameters
|
||||
public static MainFragment newInstance(boolean isHistory) {
|
||||
MainFragment fragment = new MainFragment();
|
||||
Bundle args = new Bundle();
|
||||
args.putBoolean("history", isHistory);
|
||||
fragment.setArguments(args);
|
||||
return fragment;
|
||||
}
|
||||
|
||||
public ViewPager getViewPager() {
|
||||
return mViewPager;
|
||||
}
|
||||
|
||||
public void toggleHistory() {
|
||||
isHistory = !isHistory;
|
||||
mSectionsPagerAdapter.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
if (getArguments() != null) {
|
||||
isHistory = getArguments().getBoolean("history");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
// Inflate the layout for this fragment
|
||||
mView = inflater.inflate(R.layout.fragment_main, container, false);
|
||||
AppCompatActivity activity = (AppCompatActivity) getActivity();
|
||||
Toolbar toolbar = mView.findViewById(R.id.toolbar);
|
||||
activity.setSupportActionBar(toolbar);
|
||||
|
||||
// Create the adapter that will return a fragment for each of the three
|
||||
// primary sections of the activity.
|
||||
mSectionsPagerAdapter = new SectionsPagerAdapter(getFragmentManager());
|
||||
|
||||
SharedPreferences sharedPref =
|
||||
PreferenceManager.getDefaultSharedPreferences(activity);
|
||||
|
||||
// Access database to retrieve Tabs
|
||||
try (TaskListDataAccess taskListDataAccess = new TaskListDataAccess(activity)) {
|
||||
taskLists = taskListDataAccess.getAllTaskLists();
|
||||
mSectionsPagerAdapter.notifyDataSetChanged();
|
||||
}
|
||||
if (taskLists.size() == 0) {
|
||||
Intent intent = new Intent(getContext(), TaskListActivity.class);
|
||||
startActivity(intent);
|
||||
}
|
||||
else {
|
||||
int lastOpenedList = sharedPref.getInt("last_opened_tab", 0);
|
||||
// Set up the ViewPager with the sections adapter.
|
||||
mViewPager = mView.findViewById(R.id.container);
|
||||
mViewPager.setAdapter(mSectionsPagerAdapter);
|
||||
// Open last opened tab
|
||||
mViewPager.setCurrentItem(lastOpenedList);
|
||||
|
||||
if (!getResources().getBoolean(R.bool.large_layout)) {
|
||||
|
||||
tabLayout = mView.findViewById(R.id.tabs);
|
||||
tabLayout.setupWithViewPager(mViewPager);
|
||||
|
||||
// Handles scroll detection (only available for SDK version >=23)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
toggleTabLayoutArrows(tabLayout.getScrollX());
|
||||
//tabLayout.setScrollIndicators(TabLayout.SCROLL_INDICATOR_LEFT | TabLayout.SCROLL_INDICATOR_RIGHT);
|
||||
tabLayout.setOnScrollChangeListener(new View.OnScrollChangeListener() {
|
||||
@Override
|
||||
public void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
|
||||
toggleTabLayoutArrows(scrollX);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
else {
|
||||
ListView listView = mView.findViewById(R.id.list);
|
||||
//listView.setAdapter(new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, taskLists));
|
||||
listView.setAdapter(new ArrayAdapter<>(activity, R.layout.list_tasklist_item, taskLists));
|
||||
//listView.setSelection(lastOpenedList);
|
||||
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||
mViewPager.setCurrentItem(position);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
return mView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
|
||||
// No tabs exist yet, nothing to save
|
||||
if (mViewPager == null) return;
|
||||
// Otherwise, save currently opened tab
|
||||
SharedPreferences sharedPref =
|
||||
PreferenceManager.getDefaultSharedPreferences(getContext());
|
||||
SharedPreferences.Editor editor = sharedPref.edit();
|
||||
editor.putInt("last_opened_tab", mViewPager.getCurrentItem());
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTaskListChanged(Task task, int tabPosition) {
|
||||
TaskRecyclerViewAdapter destinationTaskAdapter = getSpecificTabAdapter(tabPosition);
|
||||
if (destinationTaskAdapter != null) destinationTaskAdapter.add(task, destinationTaskAdapter.getItemCount());
|
||||
}
|
||||
|
||||
private TaskRecyclerViewAdapter getSpecificTabAdapter(int position) {
|
||||
TasksFragment taskFragment = (TasksFragment) mSectionsPagerAdapter.getRegisteredFragment(position);
|
||||
if (taskFragment == null) return null;
|
||||
View view = taskFragment.getView();
|
||||
if (view == null) return null;
|
||||
RecyclerView recyclerView = view.findViewById(R.id.task_list_view);
|
||||
if (recyclerView == null) return null;
|
||||
return (TaskRecyclerViewAdapter) recyclerView.getAdapter();
|
||||
}
|
||||
|
||||
/** Toggles scrolling arrows visibility */
|
||||
private void toggleTabLayoutArrows(int scrollX){
|
||||
// Hide left arrow when scrolled to the left
|
||||
View leftArrow = mView.findViewById(R.id.left_arrow);
|
||||
if (leftArrow != null) {
|
||||
if (scrollX <= 1) leftArrow.setVisibility(View.INVISIBLE);
|
||||
else leftArrow.setVisibility(View.VISIBLE);
|
||||
}
|
||||
// Hide right arrow when scrolled to the right
|
||||
View rightArrow = mView.findViewById(R.id.right_arrow);
|
||||
if (rightArrow != null) {
|
||||
Point size = new Point();
|
||||
getActivity().getWindowManager().getDefaultDisplay().getSize(size);
|
||||
if (scrollX == tabLayout.getChildAt(0).getMeasuredWidth() - tabLayout.getMeasuredWidth())
|
||||
rightArrow.setVisibility(View.INVISIBLE);
|
||||
else rightArrow.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A {@link FragmentPagerAdapter} that returns a fragment corresponding to
|
||||
* one of the sections/tabs/pages.
|
||||
*/
|
||||
public class SectionsPagerAdapter extends SmartFragmentStatePagerAdapter {
|
||||
|
||||
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).
|
||||
TaskList taskList = taskLists.get(position);
|
||||
return TasksFragment.newTaskListInstance(taskList.getId(), isHistory, MainFragment.this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
if (taskLists != null) {
|
||||
// Show the task lists
|
||||
return taskLists.size();
|
||||
}
|
||||
return 3;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getPageTitle(int position) {
|
||||
if (taskLists == null) return "N/A";
|
||||
return taskLists.get(position).getName();
|
||||
}
|
||||
|
||||
public List<TaskList> getAllItems(){
|
||||
return taskLists;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,174 @@
|
||||
package com.wismna.geoffroy.donext.fragments;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
import android.view.View;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.CompoundButton;
|
||||
import android.widget.DatePicker;
|
||||
import android.widget.EditText;
|
||||
import android.widget.SeekBar;
|
||||
import android.widget.Spinner;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.wismna.geoffroy.donext.R;
|
||||
import com.wismna.geoffroy.donext.dao.Task;
|
||||
import com.wismna.geoffroy.donext.dao.TaskList;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by bg45 on 2017-03-21.
|
||||
* This is Task Form dynamic dialog fragment
|
||||
*/
|
||||
|
||||
public class TaskFormDialogFragment extends DynamicDialogFragment {
|
||||
public Task getTask() {
|
||||
return task;
|
||||
}
|
||||
|
||||
/** The activity that creates an instance of this dialog fragment must
|
||||
* implement this interface in order to receive event callbacks.
|
||||
* Each method passes the DialogFragment in case the host needs to query it. */
|
||||
interface NewTaskListener {
|
||||
void onNewTaskDialogPositiveClick(DialogFragment dialog, View dialogView);
|
||||
void onNewTaskDialogNeutralClick(DialogFragment dialog);
|
||||
}
|
||||
|
||||
private TaskFormDialogFragment.NewTaskListener mListener;
|
||||
private Task task;
|
||||
private List<TaskList> taskLists;
|
||||
|
||||
public static TaskFormDialogFragment newInstance(Task task, List<TaskList> taskLists, NewTaskListener newTaskListener) {
|
||||
TaskFormDialogFragment fragment = new TaskFormDialogFragment();
|
||||
fragment.task = task;
|
||||
fragment.taskLists = taskLists;
|
||||
fragment.mListener = newTaskListener;
|
||||
fragment.setRetainInstance(true);
|
||||
return fragment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
mContentLayoutId = R.layout.content_task_form;
|
||||
Bundle args = getArguments();
|
||||
if (args != null) {
|
||||
mButtonCount = args.getInt("button_count");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
// Set Task Form specific information at that point because we are sure that the view is
|
||||
// entirely inflated (with the content fragment)
|
||||
setTaskValues();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPositiveButtonClick(View view) {
|
||||
if (view == null) return;
|
||||
EditText titleText = view.findViewById(R.id.new_task_name);
|
||||
// handle confirmation button click hereEditText titleText = (EditText) d.findViewById(R.id.new_task_name);
|
||||
if (titleText.getText().toString().matches(""))
|
||||
titleText.setError(getResources().getString(R.string.new_task_name_error));
|
||||
else {
|
||||
// Send the positive button event back to the host activity
|
||||
mListener.onNewTaskDialogPositiveClick(TaskFormDialogFragment.this, view);
|
||||
dismiss();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onNeutralButtonClick(View view) {
|
||||
mListener.onNewTaskDialogNeutralClick(TaskFormDialogFragment.this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onNegativeButtonClick() {
|
||||
dismiss();
|
||||
}
|
||||
|
||||
private void setTaskValues() {
|
||||
// Populate spinner with task lists
|
||||
Spinner spinner = (Spinner) findViewById(R.id.new_task_list);
|
||||
// Create an ArrayAdapter using the string array and a default spinner layout
|
||||
ArrayAdapter<TaskList> adapter = new ArrayAdapter<>(
|
||||
getActivity(), android.R.layout.simple_spinner_item, taskLists);
|
||||
// Specify the layout to use when the list of choices appears
|
||||
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
||||
spinner.setAdapter(adapter);
|
||||
|
||||
// Auto set list value to current tab
|
||||
Bundle args = getArguments();
|
||||
assert args != null;
|
||||
int id = args.getInt("list");
|
||||
spinner.setSelection(id);
|
||||
|
||||
CheckBox checkBox = (CheckBox) findViewById(R.id.new_task_today);
|
||||
TextView todayLabel = (TextView) findViewById(R.id.new_task_today_label);
|
||||
boolean isTodayActive = args.getBoolean("today");
|
||||
checkBox.setVisibility(isTodayActive ? View.VISIBLE : View.GONE);
|
||||
todayLabel.setVisibility(isTodayActive ? View.VISIBLE : View.GONE);
|
||||
|
||||
// Get date picker
|
||||
final DatePicker dueDatePicker = (DatePicker) findViewById(R.id.new_task_due_date);
|
||||
// Handle due date spinner depending on check box
|
||||
CheckBox setDueDate = (CheckBox) findViewById(R.id.new_task_due_date_set);
|
||||
setDueDate.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||
dueDatePicker.setVisibility(isChecked ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
});
|
||||
|
||||
// Handle priority changes
|
||||
final TextView tooltip = (TextView) findViewById(R.id.new_task_priority_tooltip);
|
||||
SeekBar seekBar = (SeekBar) findViewById(R.id.new_task_priority);
|
||||
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
|
||||
@Override
|
||||
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
|
||||
tooltip.setText(getResources().getStringArray(R.array.task_priority)[progress]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStartTrackingTouch(SeekBar seekBar) {
|
||||
tooltip.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStopTrackingTouch(SeekBar seekBar) {
|
||||
tooltip.setVisibility(View.GONE);
|
||||
}
|
||||
});
|
||||
tooltip.setText(getResources().getStringArray(R.array.task_priority)[seekBar.getProgress()]);
|
||||
// Set other properties if they exist
|
||||
if (task != null) {
|
||||
|
||||
EditText titleText = (EditText) findViewById(R.id.new_task_name);
|
||||
titleText.setText(task.getName());
|
||||
EditText descText = (EditText) findViewById(R.id.new_task_description);
|
||||
descText.setText(task.getDescription());
|
||||
|
||||
seekBar.setProgress(task.getPriority());
|
||||
|
||||
// Set Due Date
|
||||
LocalDate dueDate = task.getDueDate();
|
||||
if (dueDate != null) {
|
||||
setDueDate.setChecked(true);
|
||||
dueDatePicker.updateDate(dueDate.getYear(), dueDate.getMonthOfYear() - 1, dueDate.getDayOfMonth());
|
||||
}
|
||||
|
||||
checkBox.setChecked(task.isToday());
|
||||
}
|
||||
else {
|
||||
// Disallow past dates on new tasks
|
||||
dueDatePicker.setMinDate(LocalDate.now().toDate().getTime());
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,253 @@
|
||||
package com.wismna.geoffroy.donext.fragments;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
import android.support.v7.widget.LinearLayoutManager;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.support.v7.widget.helper.ItemTouchHelper;
|
||||
import android.view.View;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
import android.widget.Button;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.EditText;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import com.wismna.geoffroy.donext.R;
|
||||
import com.wismna.geoffroy.donext.adapters.TaskListRecyclerViewAdapter;
|
||||
import com.wismna.geoffroy.donext.dao.TaskList;
|
||||
import com.wismna.geoffroy.donext.database.TaskListDataAccess;
|
||||
import com.wismna.geoffroy.donext.helpers.TaskListTouchHelper;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A fragment representing a list of Items.
|
||||
*/
|
||||
public class TaskListsFragment extends DynamicDialogFragment implements
|
||||
TaskListRecyclerViewAdapter.TaskListRecyclerViewAdapterListener,
|
||||
ConfirmDialogFragment.ConfirmDialogListener {
|
||||
private TaskListRecyclerViewAdapter taskListRecyclerViewAdapter;
|
||||
private TaskListDataAccess taskListDataAccess;
|
||||
//private View mView;
|
||||
private ItemTouchHelper mItemTouchHelper;
|
||||
|
||||
/**
|
||||
* Mandatory empty constructor for the fragment manager to instantiate the
|
||||
* fragment (e.g. upon screen orientation changes).
|
||||
*/
|
||||
public TaskListsFragment() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
Bundle args = getArguments();
|
||||
if (args != null) {
|
||||
mButtonCount = args.getInt("button_count");
|
||||
}
|
||||
|
||||
mContentLayoutId = R.layout.fragment_tasklists;
|
||||
taskListDataAccess = new TaskListDataAccess(getContext(), TaskListDataAccess.MODE.WRITE);
|
||||
new GetTaskListsTask().execute(taskListDataAccess);
|
||||
}
|
||||
|
||||
/*@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
|
||||
mView = inflater.inflate(R.layout.fragment_tasklists, container, false);
|
||||
|
||||
Button createTaskListButton = mView.findViewById(R.id.new_task_list_button);
|
||||
createTaskListButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
EditText editText = mView.findViewById(R.id.new_task_list_name);
|
||||
String text = editText.getText().toString();
|
||||
if (text.matches("")) {
|
||||
editText.setError(getResources().getString(R.string.task_list_new_list_error));
|
||||
return;
|
||||
}
|
||||
int position = taskListRecyclerViewAdapter.getItemCount();
|
||||
|
||||
TaskList taskList = taskListDataAccess.createTaskList(text, position);
|
||||
taskListRecyclerViewAdapter.add(taskList, position);
|
||||
|
||||
editText.setText("");
|
||||
toggleVisibleCreateNewTaskListLayout(mView);
|
||||
}
|
||||
});
|
||||
|
||||
return mView;
|
||||
}*/
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
Button createTaskListButton = (Button) findViewById(R.id.new_task_list_button);
|
||||
createTaskListButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
EditText editText = (EditText) findViewById(R.id.new_task_list_name);
|
||||
String text = editText.getText().toString();
|
||||
if (text.matches("")) {
|
||||
editText.setError(getResources().getString(R.string.task_list_new_list_error));
|
||||
return;
|
||||
}
|
||||
int position = taskListRecyclerViewAdapter.getItemCount();
|
||||
|
||||
TaskList taskList = taskListDataAccess.createTaskList(text, position);
|
||||
taskListRecyclerViewAdapter.add(taskList, position);
|
||||
|
||||
editText.setText("");
|
||||
toggleVisibleCreateNewTaskListLayout();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPositiveButtonClick(View view) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onNeutralButtonClick(View view) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onNegativeButtonClick() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
clearFocus();
|
||||
super.onPause();
|
||||
taskListDataAccess.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
clearFocus();
|
||||
taskListDataAccess.open(TaskListDataAccess.MODE.WRITE);
|
||||
}
|
||||
|
||||
private void toggleVisibleCreateNewTaskListLayout() {
|
||||
LinearLayout layout = (LinearLayout) findViewById(R.id.new_task_list_layout);
|
||||
int taskListCount = taskListRecyclerViewAdapter.getItemCount();
|
||||
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(getContext());
|
||||
String maxTaskListsString = sharedPref.getString("pref_conf_max_lists", "5");
|
||||
int maxTaskLists = Integer.valueOf(maxTaskListsString);
|
||||
if (taskListCount >= maxTaskLists) layout.setVisibility(View.GONE);
|
||||
else layout.setVisibility(View.VISIBLE);
|
||||
clearFocus();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEditTextLoseFocus(TaskList taskList) {
|
||||
taskListDataAccess.updateName(taskList.getId(), taskList.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClickDeleteButton(int position, long id) {
|
||||
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(getContext());
|
||||
|
||||
if(sharedPref.getBoolean("pref_conf_tasklist_del", true)) {
|
||||
String title = getResources().getString(R.string.task_list_confirmation_delete);
|
||||
ConfirmDialogFragment confirmDialogFragment =
|
||||
ConfirmDialogFragment.newInstance(this);
|
||||
Bundle args = new Bundle();
|
||||
args.putString("message", title);
|
||||
args.putInt("button", R.string.task_confirmation_delete_button);
|
||||
args.putInt("ItemPosition", position);
|
||||
args.putLong("ItemId", id);
|
||||
confirmDialogFragment.setArguments(args);
|
||||
confirmDialogFragment.show(getFragmentManager(), title);
|
||||
}
|
||||
else deleteTaskList(position, id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConfirmDialogClick(DialogFragment dialog, ConfirmDialogFragment.ButtonEvent event) {
|
||||
// Handle never ask again checkbox
|
||||
CheckBox neverAskAgainCheckBox = dialog.getDialog().findViewById(R.id.task_confirmation_never);
|
||||
if (neverAskAgainCheckBox.isChecked()) {
|
||||
|
||||
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(getContext());
|
||||
SharedPreferences.Editor editor = sharedPref.edit();
|
||||
|
||||
editor.putBoolean("pref_conf_tasklist_del", false);
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
if (event == ConfirmDialogFragment.ButtonEvent.NO) return;
|
||||
|
||||
Bundle args = dialog.getArguments();
|
||||
assert args != null;
|
||||
deleteTaskList(args.getInt("ItemPosition"), args.getLong("ItemId"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemMove(long fromTaskId, long toTaskId, int fromPosition, int toPosition) {
|
||||
taskListDataAccess.updateOrder(fromTaskId, toPosition);
|
||||
taskListDataAccess.updateOrder(toTaskId, fromPosition);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStartDrag(RecyclerView.ViewHolder viewHolder) {
|
||||
mItemTouchHelper.startDrag(viewHolder);
|
||||
}
|
||||
|
||||
private void deleteTaskList(int position, long id)
|
||||
{
|
||||
taskListRecyclerViewAdapter.remove(position);
|
||||
taskListDataAccess.deleteTaskList(id);
|
||||
toggleVisibleCreateNewTaskListLayout();
|
||||
}
|
||||
|
||||
/** Helper method to clear focus by giving it to the parent layout */
|
||||
private void clearFocus() {
|
||||
View view = getView();
|
||||
if (view != null) {
|
||||
view.requestFocus();
|
||||
|
||||
// Hide keyboard
|
||||
InputMethodManager inputMethodManager = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
private class GetTaskListsTask extends AsyncTask<TaskListDataAccess, Void, List<TaskList>> {
|
||||
@Override
|
||||
protected List<TaskList> doInBackground(TaskListDataAccess... params) {
|
||||
TaskListDataAccess taskListDataAccess = params[0];
|
||||
return taskListDataAccess.getAllTaskLists();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(List<TaskList> taskLists) {
|
||||
super.onPostExecute(taskLists);
|
||||
taskListRecyclerViewAdapter =
|
||||
new TaskListRecyclerViewAdapter(taskLists, TaskListsFragment.this);
|
||||
|
||||
// Set the adapter
|
||||
Context context = getContext();
|
||||
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.task_lists_view);
|
||||
recyclerView.setLayoutManager(new LinearLayoutManager(context));
|
||||
recyclerView.setAdapter(taskListRecyclerViewAdapter);
|
||||
|
||||
// Set the Touch Helper
|
||||
ItemTouchHelper.Callback callback = new TaskListTouchHelper(taskListRecyclerViewAdapter);
|
||||
mItemTouchHelper = new ItemTouchHelper(callback);
|
||||
mItemTouchHelper.attachToRecyclerView(recyclerView);
|
||||
|
||||
toggleVisibleCreateNewTaskListLayout();
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,477 @@
|
||||
package com.wismna.geoffroy.donext.fragments;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.res.Resources;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.design.widget.Snackbar;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v4.app.FragmentManager;
|
||||
import android.support.v4.app.FragmentTransaction;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.support.v4.view.ViewPager;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.support.v7.widget.helper.ItemTouchHelper;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewTreeObserver;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.DatePicker;
|
||||
import android.widget.EditText;
|
||||
import android.widget.SeekBar;
|
||||
import android.widget.Spinner;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.wismna.geoffroy.donext.R;
|
||||
import com.wismna.geoffroy.donext.adapters.TaskRecyclerViewAdapter;
|
||||
import com.wismna.geoffroy.donext.dao.Task;
|
||||
import com.wismna.geoffroy.donext.dao.TaskList;
|
||||
import com.wismna.geoffroy.donext.database.TaskDataAccess;
|
||||
import com.wismna.geoffroy.donext.database.TaskListDataAccess;
|
||||
import com.wismna.geoffroy.donext.helpers.TaskTouchHelper;
|
||||
import com.wismna.geoffroy.donext.listeners.RecyclerItemClickListener;
|
||||
import com.wismna.geoffroy.donext.widgets.DividerItemDecoration;
|
||||
import com.wismna.geoffroy.donext.widgets.NoScrollingLayoutManager;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A fragment representing a list of Items.
|
||||
*/
|
||||
public class TasksFragment extends Fragment implements
|
||||
TaskFormDialogFragment.NewTaskListener,
|
||||
ConfirmDialogFragment.ConfirmDialogListener,
|
||||
TaskTouchHelper.TaskTouchHelperAdapter{
|
||||
|
||||
interface TaskChangedAdapter {
|
||||
void onTaskListChanged(Task task, int tabPosition);
|
||||
}
|
||||
|
||||
private static final String TASK_LIST_ID = "task_list_id";
|
||||
private long taskListId = -1;
|
||||
private boolean isTodayView = true;
|
||||
private boolean isHistory = false;
|
||||
private TaskRecyclerViewAdapter taskRecyclerViewAdapter;
|
||||
private View view;
|
||||
private RecyclerView recyclerView;
|
||||
private TaskChangedAdapter mAdapter;
|
||||
private Snackbar snackbar;
|
||||
|
||||
/**
|
||||
* Mandatory empty constructor for the fragment manager to instantiate the
|
||||
* fragment (e.g. upon screen orientation changes).
|
||||
*/
|
||||
public TasksFragment() {
|
||||
}
|
||||
|
||||
public static TasksFragment newTaskListInstance(long taskListId, boolean isHistory,
|
||||
TaskChangedAdapter taskChangedAdapter) {
|
||||
TasksFragment fragment = new TasksFragment();
|
||||
Bundle args = new Bundle();
|
||||
args.putLong(TASK_LIST_ID, taskListId);
|
||||
args.putBoolean("history", isHistory);
|
||||
fragment.setArguments(args);
|
||||
fragment.mAdapter = taskChangedAdapter;
|
||||
fragment.isTodayView = false;
|
||||
fragment.setRetainInstance(true);
|
||||
return fragment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
if (getArguments() != null) {
|
||||
taskListId = getArguments().getLong(TASK_LIST_ID);
|
||||
isHistory = getArguments().getBoolean("history");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
view = inflater.inflate(R.layout.fragment_tasks, container, false);
|
||||
final Context context = view.getContext();
|
||||
|
||||
// Set the Recycler view
|
||||
recyclerView = view.findViewById(R.id.task_list_view);
|
||||
recyclerView.setLayoutManager(new NoScrollingLayoutManager(context));
|
||||
|
||||
// Set RecyclerView Adapter
|
||||
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(getContext());
|
||||
|
||||
// Get all tasks
|
||||
try (TaskDataAccess taskDataAccess = new TaskDataAccess(view.getContext())) {
|
||||
taskRecyclerViewAdapter = new TaskRecyclerViewAdapter(
|
||||
isTodayView? taskDataAccess.getTodayTasks() : taskDataAccess.getAllTasksFromList(taskListId, isHistory),
|
||||
Integer.valueOf(sharedPref.getString("pref_conf_task_layout", "1")), isTodayView);
|
||||
}
|
||||
recyclerView.setAdapter(taskRecyclerViewAdapter);
|
||||
|
||||
// Set ItemTouch helper in RecyclerView to handle swipe move on elements
|
||||
final Resources resources = getResources();
|
||||
ItemTouchHelper.Callback callback = new TaskTouchHelper(this,
|
||||
ContextCompat.getColor(context, R.color.colorPrimary),
|
||||
ContextCompat.getColor(context, R.color.colorAccent));
|
||||
ItemTouchHelper helper = new ItemTouchHelper(callback);
|
||||
helper.attachToRecyclerView(recyclerView);
|
||||
|
||||
// Implements touch listener to add click detection
|
||||
recyclerView.addOnItemTouchListener(
|
||||
new RecyclerItemClickListener(context, new RecyclerItemClickListener.OnItemClickListener() {
|
||||
@Override
|
||||
public void onItemClick(View view, int position) {
|
||||
boolean isLargeLayout = resources.getBoolean(R.bool.large_layout);
|
||||
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(getContext());
|
||||
Bundle args = new Bundle();
|
||||
args.putInt("position", position);
|
||||
args.putBoolean("today", sharedPref.getBoolean("pref_conf_today_enable", false));
|
||||
args.putBoolean("neutral", true);
|
||||
args.putString("button_positive", getString(R.string.new_task_save));
|
||||
args.putString("button_negative", getString(R.string.new_task_cancel));
|
||||
args.putString("button_neutral", getString(R.string.new_task_delete));
|
||||
|
||||
// Set current tab value to new task dialog
|
||||
ViewPager viewPager = getActivity().findViewById(R.id.container);
|
||||
List<TaskList> taskLists;
|
||||
Task task = taskRecyclerViewAdapter.getItem(position);
|
||||
if (viewPager != null) {
|
||||
taskLists = ((MainFragment.SectionsPagerAdapter) viewPager.getAdapter()).getAllItems();
|
||||
args.putInt("list", viewPager.getCurrentItem());
|
||||
}
|
||||
else {
|
||||
try (TaskListDataAccess taskListDataAccess = new TaskListDataAccess(getActivity())) {
|
||||
taskLists = taskListDataAccess.getAllTaskLists();
|
||||
}
|
||||
for (TaskList taskList :
|
||||
taskLists) {
|
||||
if (taskList.getId() == task.getTaskListId()) {
|
||||
args.putInt("list", taskLists.indexOf(taskList));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FragmentManager manager = getFragmentManager();
|
||||
TaskFormDialogFragment taskDialogFragment = TaskFormDialogFragment.newInstance(
|
||||
task, taskLists, TasksFragment.this);
|
||||
taskDialogFragment.setArguments(args);
|
||||
|
||||
// Open the fragment as a dialog or as full-screen depending on screen size
|
||||
String title = getString(R.string.action_edit_task);
|
||||
if (isLargeLayout) {
|
||||
taskDialogFragment.show(manager, title);
|
||||
}
|
||||
else {
|
||||
// The device is smaller, so show the fragment fullscreen
|
||||
FragmentTransaction transaction = manager.beginTransaction();
|
||||
// For a little polish, specify a transition animation
|
||||
transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
|
||||
// To make it fullscreen, use the 'content' root view as the container
|
||||
// for the fragment, which is always the root view for the activity
|
||||
transaction.add(android.R.id.content, taskDialogFragment, title)
|
||||
.addToBackStack(null).commit();
|
||||
}
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
// Handle updating total counts in a listener to be sure that the layout is available
|
||||
recyclerView.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
|
||||
@Override
|
||||
public boolean onPreDraw() {
|
||||
// isAdded is tested to prevent an IllegalStateException when fast switching between tabs
|
||||
if (!isAdded()) return true;
|
||||
Resources resources = getResources();
|
||||
|
||||
// Update total cycle count
|
||||
int totalCycles = taskRecyclerViewAdapter.getCycleCount();
|
||||
TextView totalCyclesView = view.findViewById(R.id.total_task_cycles);
|
||||
if (totalCycles != 0)
|
||||
totalCyclesView.setText(resources.getQuantityString(R.plurals.task_total_cycles, totalCycles, totalCycles));
|
||||
else totalCyclesView.setText("");
|
||||
|
||||
// Update total tasks
|
||||
int totalTasks = taskRecyclerViewAdapter.getItemCount();
|
||||
TextView totalTasksView = view.findViewById(R.id.total_task_count);
|
||||
View noMoreTasks = view.findViewById(R.id.no_more_tasks);
|
||||
if (totalTasks == 0) {
|
||||
noMoreTasks.setVisibility(View.VISIBLE);
|
||||
totalTasksView.setVisibility(View.GONE);
|
||||
}
|
||||
else {
|
||||
noMoreTasks.setVisibility(View.GONE);
|
||||
totalTasksView.setVisibility(View.VISIBLE);
|
||||
totalTasksView.setText(resources.getQuantityString(R.plurals.task_total, totalTasks, totalTasks));
|
||||
}
|
||||
|
||||
// Update remaining tasks
|
||||
TextView remainingTasksView = view.findViewById(R.id.remaining_task_count);
|
||||
NoScrollingLayoutManager layoutManager = (NoScrollingLayoutManager) recyclerView.getLayoutManager();
|
||||
int remainingTaskCount = totalTasks - layoutManager.findLastVisibleItemPosition() - 1;
|
||||
if (remainingTaskCount == 0) remainingTasksView.setText("");
|
||||
else remainingTasksView.setText(resources.getQuantityString(R.plurals.task_remaining, remainingTaskCount, remainingTaskCount));
|
||||
|
||||
//recyclerView.getViewTreeObserver().removeOnPreDrawListener(this);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
recyclerView.addItemDecoration(new DividerItemDecoration(getActivity()));
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
if (snackbar != null) snackbar.dismiss();
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConfirmDialogClick(DialogFragment dialog, ConfirmDialogFragment.ButtonEvent event) {
|
||||
Bundle args = dialog.getArguments();
|
||||
int itemPosition = args.getInt("ItemPosition");
|
||||
int direction = args.getInt("Direction");
|
||||
|
||||
// Handle never ask again checkbox
|
||||
CheckBox neverAskAgainCheckBox = dialog.getDialog().findViewById(R.id.task_confirmation_never);
|
||||
if (neverAskAgainCheckBox.isChecked()) {
|
||||
|
||||
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(getContext());
|
||||
SharedPreferences.Editor editor = sharedPref.edit();
|
||||
|
||||
// Set system settings
|
||||
switch (direction) {
|
||||
case ItemTouchHelper.LEFT:
|
||||
editor.putBoolean("pref_conf_done", false);
|
||||
break;
|
||||
case ItemTouchHelper.RIGHT:
|
||||
editor.putBoolean("pref_conf_next", false);
|
||||
break;
|
||||
case -1:
|
||||
editor.putBoolean("pref_conf_del", false);
|
||||
break;
|
||||
}
|
||||
editor.apply();
|
||||
}
|
||||
if (event == ConfirmDialogFragment.ButtonEvent.YES) {
|
||||
PerformTaskAction(itemPosition, direction);
|
||||
}
|
||||
else if(event == ConfirmDialogFragment.ButtonEvent.NO) {
|
||||
taskRecyclerViewAdapter.notifyItemChanged(itemPosition);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNewTaskDialogPositiveClick(DialogFragment dialog, View dialogView) {
|
||||
// Get the dialog fragment
|
||||
if (dialogView == null) return;
|
||||
long id = 0;
|
||||
Task task = ((TaskFormDialogFragment)dialog).getTask();
|
||||
if (task != null) id = task.getId();
|
||||
|
||||
// Get the controls
|
||||
Spinner listSpinner = dialogView.findViewById(R.id.new_task_list);
|
||||
EditText nameText = dialogView.findViewById(R.id.new_task_name);
|
||||
EditText descText = dialogView.findViewById(R.id.new_task_description);
|
||||
SeekBar seekBar = dialogView.findViewById(R.id.new_task_priority);
|
||||
CheckBox setDueDate = dialogView.findViewById(R.id.new_task_due_date_set);
|
||||
DatePicker dueDatePicker = dialogView.findViewById(R.id.new_task_due_date);
|
||||
TaskList taskList = (TaskList) listSpinner.getSelectedItem();
|
||||
CheckBox todayList = dialogView.findViewById(R.id.new_task_today);
|
||||
boolean isToday = todayList.isChecked();
|
||||
// Add the task to the database
|
||||
try (TaskDataAccess taskDataAccess = new TaskDataAccess(view.getContext(), TaskDataAccess.MODE.WRITE)) {
|
||||
Task newTask = taskDataAccess.createOrUpdateTask(id,
|
||||
nameText.getText().toString(),
|
||||
descText.getText().toString(),
|
||||
seekBar.getProgress(),
|
||||
taskList.getId(),
|
||||
setDueDate.isChecked() ?
|
||||
new LocalDate(dueDatePicker.getYear(),
|
||||
dueDatePicker.getMonth() + 1,
|
||||
dueDatePicker.getDayOfMonth()).toString()
|
||||
: "",
|
||||
isToday);
|
||||
|
||||
Bundle args = dialog.getArguments();
|
||||
// Should never happen because we will have to be on this tab to open the dialog
|
||||
if (taskRecyclerViewAdapter == null) return;
|
||||
|
||||
// Add the task
|
||||
if (task == null) {
|
||||
// If the new task is added to another task list, update the tab
|
||||
if (mAdapter != null && taskListId != taskList.getId()) {
|
||||
mAdapter.onTaskListChanged(newTask, listSpinner.getSelectedItemPosition());
|
||||
}
|
||||
// Otherwise add it to the current one
|
||||
else {
|
||||
taskRecyclerViewAdapter.add(newTask, 0);
|
||||
recyclerView.scrollToPosition(0);
|
||||
}
|
||||
}
|
||||
// Update the task
|
||||
else {
|
||||
int position = args.getInt("position");
|
||||
// Check if task list was changed
|
||||
if ((isTodayView && !isToday) || (!isTodayView && task.getTaskListId() != taskList.getId()))
|
||||
{
|
||||
// Remove item from current tab
|
||||
taskRecyclerViewAdapter.remove(position);
|
||||
|
||||
// Add it to the corresponding tab provided it is already instantiated
|
||||
if (mAdapter != null) mAdapter.onTaskListChanged(newTask, listSpinner.getSelectedItemPosition());
|
||||
} else {
|
||||
taskRecyclerViewAdapter.update(newTask, position);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNewTaskDialogNeutralClick(DialogFragment dialog) {
|
||||
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(getContext());
|
||||
boolean showDialog = sharedPref.getBoolean("pref_conf_del", true);
|
||||
Bundle args = dialog.getArguments();
|
||||
|
||||
// Delete task from Adapter
|
||||
final int itemPosition = args.getInt("position");
|
||||
|
||||
if (showDialog) {
|
||||
String title = getResources().getString(R.string.task_confirmation_delete_text);
|
||||
ConfirmDialogFragment confirmDialogFragment =
|
||||
ConfirmDialogFragment.newInstance(this);
|
||||
Bundle confirmArgs = new Bundle();
|
||||
confirmArgs.putString("message", title);
|
||||
confirmArgs.putInt("button", R.string.task_confirmation_delete_button);
|
||||
confirmArgs.putInt("ItemPosition", itemPosition);
|
||||
confirmArgs.putInt("Direction", -1);
|
||||
confirmDialogFragment.setArguments(confirmArgs);
|
||||
confirmDialogFragment.show(getFragmentManager(), title);
|
||||
}
|
||||
else {
|
||||
PerformTaskAction(itemPosition, -1);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemSwiped(int itemPosition, int direction) {
|
||||
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(getContext());
|
||||
String title = "";
|
||||
boolean showDialog = false;
|
||||
int buttonLabel = -1;
|
||||
|
||||
switch (direction)
|
||||
{
|
||||
// Mark item as Done
|
||||
case ItemTouchHelper.LEFT:
|
||||
title = getResources().getString(R.string.task_confirmation_done_text);
|
||||
showDialog = sharedPref.getBoolean("pref_conf_done", true);
|
||||
buttonLabel = R.string.task_confirmation_done_button;
|
||||
break;
|
||||
// Increase task cycle count
|
||||
case ItemTouchHelper.RIGHT:
|
||||
title = getResources().getString(R.string.task_confirmation_next_text);
|
||||
showDialog = sharedPref.getBoolean("pref_conf_next", true);
|
||||
buttonLabel = R.string.task_confirmation_next_button;
|
||||
break;
|
||||
}
|
||||
if (showDialog) {
|
||||
ConfirmDialogFragment confirmDialogFragment =
|
||||
ConfirmDialogFragment.newInstance(this);
|
||||
Bundle args = new Bundle();
|
||||
args.putString("message", title);
|
||||
args.putInt("button", buttonLabel);
|
||||
args.putInt("ItemPosition", itemPosition);
|
||||
args.putInt("Direction", direction);
|
||||
confirmDialogFragment.setArguments(args);
|
||||
confirmDialogFragment.show(getFragmentManager(), title);
|
||||
}
|
||||
else PerformTaskAction(itemPosition, direction);
|
||||
}
|
||||
|
||||
/** Performs an action on a task: done, next or delete */
|
||||
private void PerformTaskAction(final int itemPosition, final int direction) {
|
||||
final long itemId = taskRecyclerViewAdapter.getItemId(itemPosition);
|
||||
final Task task = taskRecyclerViewAdapter.getItem(itemPosition);
|
||||
String action = "";
|
||||
Resources resources = getResources();
|
||||
|
||||
taskRecyclerViewAdapter.remove(itemPosition);
|
||||
|
||||
switch (direction)
|
||||
{
|
||||
// Mark item as Done
|
||||
case ItemTouchHelper.LEFT:
|
||||
action = resources.getString(R.string.snackabar_action_done);
|
||||
break;
|
||||
// Increase task cycle count
|
||||
case ItemTouchHelper.RIGHT:
|
||||
action = resources.getString(R.string.snackabar_action_next);
|
||||
task.setCycle(task.getCycle() + 1);
|
||||
taskRecyclerViewAdapter.add(task, taskRecyclerViewAdapter.getItemCount());
|
||||
break;
|
||||
case -1:
|
||||
FragmentManager manager = getFragmentManager();
|
||||
DialogFragment dialog = (DialogFragment) manager.findFragmentByTag(getString(R.string.action_edit_task));
|
||||
if (dialog != null) dialog.dismiss();
|
||||
action = resources.getString(R.string.snackabar_action_deleted);
|
||||
break;
|
||||
}
|
||||
|
||||
// Setup the snack bar
|
||||
snackbar = Snackbar.make(view, resources.getString(R.string.snackabar_label, action), Snackbar.LENGTH_LONG)
|
||||
.setAction(resources.getString(R.string.snackabar_button), new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
// Undo adapter changes
|
||||
switch (direction) {
|
||||
// Nothing special to do for done
|
||||
case ItemTouchHelper.LEFT:
|
||||
break;
|
||||
// Remove the last item
|
||||
case ItemTouchHelper.RIGHT:
|
||||
taskRecyclerViewAdapter.remove(taskRecyclerViewAdapter.getItemCount() - 1);
|
||||
task.setCycle(task.getCycle() - 1);
|
||||
break;
|
||||
// Nothing special to do for delete
|
||||
case -1:
|
||||
break;
|
||||
}
|
||||
// Reset the first item
|
||||
taskRecyclerViewAdapter.add(task, itemPosition);
|
||||
recyclerView.scrollToPosition(0);
|
||||
}
|
||||
});
|
||||
snackbar.addCallback(new Snackbar.Callback() {
|
||||
@Override
|
||||
public void onDismissed(Snackbar snackbar, int event) {
|
||||
super.onDismissed(snackbar, event);
|
||||
// When clicked on undo, do not write to DB
|
||||
if (event == DISMISS_EVENT_ACTION) return;
|
||||
|
||||
// Commit the changes to DB
|
||||
try (TaskDataAccess taskDataAccess = new TaskDataAccess(view.getContext(), TaskDataAccess.MODE.WRITE)) {
|
||||
switch (direction) {
|
||||
// Mark item as Done
|
||||
case ItemTouchHelper.LEFT:
|
||||
taskDataAccess.setDone(itemId);
|
||||
break;
|
||||
// Increase task cycle count
|
||||
case ItemTouchHelper.RIGHT:
|
||||
taskDataAccess.increaseCycle(task.getCycle(), itemId);
|
||||
break;
|
||||
case -1:
|
||||
// Delete the task
|
||||
taskDataAccess.deleteTask(itemId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}).show();
|
||||
}
|
||||
}
|
@@ -0,0 +1,146 @@
|
||||
package com.wismna.geoffroy.donext.fragments;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.text.Editable;
|
||||
import android.text.TextWatcher;
|
||||
import android.view.View;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.EditText;
|
||||
import android.widget.ListView;
|
||||
|
||||
import com.wismna.geoffroy.donext.R;
|
||||
import com.wismna.geoffroy.donext.adapters.TodayArrayAdapter;
|
||||
import com.wismna.geoffroy.donext.dao.Task;
|
||||
import com.wismna.geoffroy.donext.database.TaskDataAccess;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by bg45 on 2017-03-21.
|
||||
* This is the Today Form dynamic dialog fragment
|
||||
*/
|
||||
|
||||
public class TodayFormDialogFragment extends DynamicDialogFragment {
|
||||
/** The activity that creates an instance of this dialog fragment must
|
||||
* implement this interface in order to receive event callbacks.
|
||||
* Each method passes the DialogFragment in case the host needs to query it. */
|
||||
public interface TodayTaskListener {
|
||||
void onTodayTaskDialogPositiveClick(View dialogView);
|
||||
void onTodayTasksUpdated();
|
||||
}
|
||||
private TodayFormDialogFragment.TodayTaskListener mListener;
|
||||
private final List<Task> mUpdatedTasks = new ArrayList<>();
|
||||
|
||||
public static TodayFormDialogFragment newInstance(TodayTaskListener todayTaskListener) {
|
||||
TodayFormDialogFragment fragment = new TodayFormDialogFragment();
|
||||
|
||||
fragment.mListener = todayTaskListener;
|
||||
fragment.setRetainInstance(true);
|
||||
return fragment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
mContentLayoutId = R.layout.content_today_form;
|
||||
// Load the tasks asynchronously
|
||||
new LoadTasks().execute(getActivity());
|
||||
}
|
||||
|
||||
private void setLayoutValues(List<Task> tasks) {
|
||||
EditText editText = (EditText) findViewById(R.id.today_search);
|
||||
final ListView listView = (ListView) findViewById(R.id.today_tasks);
|
||||
final TodayArrayAdapter adapter = new TodayArrayAdapter(getActivity(), tasks);
|
||||
listView.setAdapter(adapter);
|
||||
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||
// Set Today date for the task
|
||||
Task task = adapter.getItem(position);
|
||||
if (task == null) return;
|
||||
task.setTodayDate(task.isToday() ? "" : LocalDate.now().toString());
|
||||
// Maintain a list of actually updated tasks to commit to DB
|
||||
if (!mUpdatedTasks.contains(task)) mUpdatedTasks.add(task);
|
||||
else mUpdatedTasks.remove(task);
|
||||
// Refresh the view
|
||||
adapter.notifyDataSetChanged();
|
||||
}
|
||||
});
|
||||
editText.addTextChangedListener(new TextWatcher() {
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
adapter.getFilter().filter(s);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(Editable s) {
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPositiveButtonClick(View view) {
|
||||
mListener.onTodayTaskDialogPositiveClick(view);
|
||||
// Only commit the updated tasks to DB
|
||||
new UpdateTasks().execute(mUpdatedTasks.toArray(new Task[mUpdatedTasks.size()]));
|
||||
dismiss();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onNeutralButtonClick(View view) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onNegativeButtonClick() {
|
||||
dismiss();
|
||||
}
|
||||
|
||||
private class LoadTasks extends AsyncTask<Context, Void, List<Task>> {
|
||||
@Override
|
||||
protected List<Task> doInBackground(Context... params) {
|
||||
try(TaskDataAccess taskDataAccess = new TaskDataAccess(params[0])) {
|
||||
return taskDataAccess.getAllTasks();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(List<Task> tasks) {
|
||||
super.onPostExecute(tasks);
|
||||
setLayoutValues(tasks);
|
||||
}
|
||||
}
|
||||
|
||||
private class UpdateTasks extends AsyncTask<Task, Void, Integer> {
|
||||
@Override
|
||||
protected Integer doInBackground(Task... params) {
|
||||
int elementsUpdated = 0;
|
||||
try (TaskDataAccess taskDataAccess = new TaskDataAccess(getActivity(), TaskDataAccess.MODE.WRITE)) {
|
||||
for (Task task :
|
||||
params) {
|
||||
taskDataAccess.updateTodayTasks(task.getId(), task.isToday());
|
||||
elementsUpdated++;
|
||||
}
|
||||
}
|
||||
return elementsUpdated;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Integer integer) {
|
||||
super.onPostExecute(integer);
|
||||
mListener.onTodayTasksUpdated();
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,56 @@
|
||||
package com.wismna.geoffroy.donext.helpers;
|
||||
|
||||
import android.graphics.Color;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.support.v7.widget.helper.ItemTouchHelper;
|
||||
|
||||
/**
|
||||
* Created by geoffroy on 15-12-30.
|
||||
* Helper class that handles all drags events on a TaskList
|
||||
*/
|
||||
public class TaskListTouchHelper extends ItemTouchHelper.SimpleCallback {
|
||||
|
||||
public interface TaskListTouchHelperAdapter {
|
||||
boolean onItemMove(int fromPosition, int toPosition);
|
||||
}
|
||||
|
||||
private final TaskListTouchHelperAdapter mAdapter;
|
||||
|
||||
public TaskListTouchHelper(TaskListTouchHelperAdapter adapter) {
|
||||
super(ItemTouchHelper.UP | ItemTouchHelper.DOWN, 0);
|
||||
mAdapter = adapter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
|
||||
return mAdapter.onItemMove(viewHolder.getAdapterPosition(), target.getAdapterPosition());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
|
||||
// No swipe moves
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLongPressDragEnabled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
|
||||
if (actionState != ItemTouchHelper.ACTION_STATE_IDLE)
|
||||
{
|
||||
viewHolder.itemView.setBackgroundColor(Color.LTGRAY);
|
||||
}
|
||||
|
||||
super.onSelectedChanged(viewHolder, actionState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
|
||||
super.clearView(recyclerView, viewHolder);
|
||||
|
||||
viewHolder.itemView.setAlpha(1.0f);
|
||||
viewHolder.itemView.setBackgroundColor(0);
|
||||
}
|
||||
}
|
@@ -0,0 +1,106 @@
|
||||
package com.wismna.geoffroy.donext.helpers;
|
||||
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Rect;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.support.v7.widget.helper.ItemTouchHelper;
|
||||
import android.text.Layout;
|
||||
import android.text.StaticLayout;
|
||||
import android.text.TextPaint;
|
||||
import android.view.View;
|
||||
|
||||
import com.wismna.geoffroy.donext.R;
|
||||
|
||||
/**
|
||||
* Created by geoffroy on 15-12-04.
|
||||
* Helper class that handles all swipe events on a Task
|
||||
*/
|
||||
public class TaskTouchHelper extends ItemTouchHelper.SimpleCallback {
|
||||
public interface TaskTouchHelperAdapter {
|
||||
void onItemSwiped(int position, int direction);
|
||||
}
|
||||
|
||||
private final TaskTouchHelperAdapter mAdapter;
|
||||
private int colorRight;
|
||||
private int colorLeft;
|
||||
|
||||
public TaskTouchHelper(TaskTouchHelperAdapter adapter, int colorRight, int colorLeft){
|
||||
// No drag moves, no swipes (except for 1st element, see getSwipeDirs method)
|
||||
super(0, 0);
|
||||
this.colorRight = colorRight;
|
||||
this.colorLeft = colorLeft;
|
||||
this.mAdapter = adapter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSwipeDirs(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
|
||||
// Allow both directions swiping on first item, only left on the others
|
||||
if (viewHolder.getAdapterPosition() == 0)
|
||||
return ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
|
||||
else return super.getSwipeDirs(recyclerView, viewHolder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
|
||||
mAdapter.onItemSwiped(viewHolder.getAdapterPosition(), direction);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder,
|
||||
float dX, float dY, int actionState, boolean isCurrentlyActive) {
|
||||
// Get RecyclerView item from the ViewHolder
|
||||
View itemView = viewHolder.itemView;
|
||||
|
||||
if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) {
|
||||
|
||||
if (dX > 0) {
|
||||
Rect rect = new Rect(itemView.getLeft(), itemView.getTop(), (int) dX,
|
||||
itemView.getBottom());
|
||||
setBackground(c, itemView, rect, dX, dY,
|
||||
colorLeft, R.string.task_confirmation_next_button);
|
||||
} else {
|
||||
// Draw Rect with varying left side, equal to the item's right side plus negative displacement dX
|
||||
Rect rect = new Rect(itemView.getRight() + (int)dX, itemView.getTop(),
|
||||
itemView.getRight(), itemView.getBottom());
|
||||
setBackground(c, itemView, rect, dX, dY,
|
||||
colorRight, R.string.task_confirmation_done_button);
|
||||
}
|
||||
}
|
||||
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
|
||||
}
|
||||
|
||||
private void setBackground(Canvas c, View itemView,
|
||||
Rect rect, float dX, float dY, int color, int textId) {
|
||||
|
||||
TextPaint textPaint = new TextPaint();
|
||||
textPaint.setAntiAlias(true);
|
||||
textPaint.setTextSize(25 * itemView.getResources().getDisplayMetrics().density);
|
||||
textPaint.setColor(Color.WHITE);
|
||||
|
||||
int heightOffset = itemView.getHeight() / 2 - (int)textPaint.getTextSize() / 2;
|
||||
int widthOffset = 30;
|
||||
|
||||
Paint background = new Paint();
|
||||
// Set your color for negative displacement
|
||||
background.setColor(color);
|
||||
// Draw Rect with varying left side, equal to the item's right side plus negative displacement dX
|
||||
c.drawRect(rect, background);
|
||||
|
||||
// Draw text in the rectangle
|
||||
String text = itemView.getResources().getString(textId).toUpperCase();
|
||||
int width = (int) textPaint.measureText(text);
|
||||
float textXCoordinate;
|
||||
if (dX > 0) textXCoordinate = rect.left + widthOffset;
|
||||
else textXCoordinate = rect.right - width - widthOffset;
|
||||
c.translate(textXCoordinate, dY + heightOffset);
|
||||
StaticLayout staticLayout = new StaticLayout(text, textPaint, width, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0, false);
|
||||
staticLayout.draw(c);
|
||||
}
|
||||
}
|
@@ -0,0 +1,52 @@
|
||||
package com.wismna.geoffroy.donext.listeners;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.view.GestureDetector;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
|
||||
/**
|
||||
* Created by geoffroy on 15-12-02.
|
||||
* Listener class on RecyclerView to intercept touch events
|
||||
*/
|
||||
public class RecyclerItemClickListener implements RecyclerView.OnItemTouchListener {
|
||||
private final OnItemClickListener mListener;
|
||||
|
||||
public interface OnItemClickListener {
|
||||
void onItemClick(View view, int position);
|
||||
}
|
||||
|
||||
private final GestureDetector mGestureDetector;
|
||||
|
||||
public RecyclerItemClickListener(Context context, OnItemClickListener listener) {
|
||||
mListener = listener;
|
||||
mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
|
||||
@Override
|
||||
public boolean onSingleTapUp(MotionEvent e) {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onInterceptTouchEvent(RecyclerView view, MotionEvent e) {
|
||||
View childView = view.findChildViewUnder(e.getX(), e.getY());
|
||||
//int childId = view.getChildAdapterPosition(childView);
|
||||
if (childView != null && mListener != null && mGestureDetector.onTouchEvent(e)) {
|
||||
mListener.onItemClick(childView, view.getChildAdapterPosition(childView));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTouchEvent(RecyclerView view, MotionEvent motionEvent) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
|
||||
|
||||
}
|
||||
}
|
@@ -0,0 +1,54 @@
|
||||
package com.wismna.geoffroy.donext.widgets;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.view.View;
|
||||
|
||||
/**
|
||||
* Created by geoffroy on 16-01-11.
|
||||
* Displays dividers between RecyclerView items
|
||||
*/
|
||||
public class DividerItemDecoration extends RecyclerView.ItemDecoration {
|
||||
|
||||
private static final int[] ATTRS = new int[]{android.R.attr.listDivider};
|
||||
|
||||
private final Drawable mDivider;
|
||||
|
||||
/**
|
||||
* Default divider will be used
|
||||
*/
|
||||
public DividerItemDecoration(Context context) {
|
||||
final TypedArray styledAttributes = context.obtainStyledAttributes(ATTRS);
|
||||
mDivider = styledAttributes.getDrawable(0);
|
||||
styledAttributes.recycle();
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom divider will be used
|
||||
*/
|
||||
/*public DividerItemDecoration(Context context, int resId) {
|
||||
mDivider = ContextCompat.getDrawable(context, resId);
|
||||
}*/
|
||||
|
||||
@Override
|
||||
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
|
||||
int left = parent.getPaddingLeft();
|
||||
int right = parent.getWidth() - parent.getPaddingRight();
|
||||
|
||||
int childCount = parent.getChildCount();
|
||||
for (int i = 0; i < childCount; i++) {
|
||||
View child = parent.getChildAt(i);
|
||||
|
||||
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
|
||||
|
||||
int top = child.getBottom() + params.bottomMargin;
|
||||
int bottom = top + mDivider.getIntrinsicHeight();
|
||||
|
||||
mDivider.setBounds(left, top, right, bottom);
|
||||
mDivider.draw(c);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,20 @@
|
||||
package com.wismna.geoffroy.donext.widgets;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.v7.widget.LinearLayoutManager;
|
||||
|
||||
/**
|
||||
* Created by geoffroy on 15-12-21.
|
||||
* Custom Layout Manager that disables vertical scrolling for the RecyclerView
|
||||
*/
|
||||
public class NoScrollingLayoutManager extends LinearLayoutManager {
|
||||
|
||||
public NoScrollingLayoutManager(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canScrollVertically() {
|
||||
return false;
|
||||
}
|
||||
}
|
@@ -0,0 +1,33 @@
|
||||
package com.wismna.geoffroy.donext.widgets;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.v4.view.ViewPager;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.MotionEvent;
|
||||
|
||||
/**
|
||||
* Created by geoffroy on 15-12-04.
|
||||
* Custom ViewPager to forbid vertical swiping between tabs
|
||||
*/
|
||||
public class NonSwipeableViewPager extends ViewPager {
|
||||
|
||||
public NonSwipeableViewPager(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public NonSwipeableViewPager(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onInterceptTouchEvent(MotionEvent event) {
|
||||
// Never allow swiping to switch between pages
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
// Never allow swiping to switch between pages
|
||||
return false;
|
||||
}
|
||||
}
|
BIN
app/src/main/res/drawable-hdpi-v11/ic_stat_name.png
Normal file
After Width: | Height: | Size: 331 B |
BIN
app/src/main/res/drawable-hdpi-v9/ic_stat_name.png
Normal file
After Width: | Height: | Size: 392 B |
BIN
app/src/main/res/drawable-hdpi/ic_access_alarm.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
app/src/main/res/drawable-hdpi/ic_add.png
Normal file
After Width: | Height: | Size: 223 B |
BIN
app/src/main/res/drawable-hdpi/ic_create_new_folder_dark.png
Normal file
After Width: | Height: | Size: 335 B |
BIN
app/src/main/res/drawable-hdpi/ic_format_size_dark.png
Normal file
After Width: | Height: | Size: 206 B |
After Width: | Height: | Size: 153 B |
After Width: | Height: | Size: 150 B |
BIN
app/src/main/res/drawable-hdpi/ic_list_white_24dp.png
Normal file
After Width: | Height: | Size: 116 B |
BIN
app/src/main/res/drawable-hdpi/ic_reorder.png
Normal file
After Width: | Height: | Size: 166 B |
BIN
app/src/main/res/drawable-hdpi/ic_stat_name.png
Normal file
After Width: | Height: | Size: 961 B |
BIN
app/src/main/res/drawable-mdpi-v11/ic_stat_name.png
Normal file
After Width: | Height: | Size: 255 B |
BIN
app/src/main/res/drawable-mdpi-v9/ic_stat_name.png
Normal file
After Width: | Height: | Size: 304 B |
BIN
app/src/main/res/drawable-mdpi/ic_access_alarm.png
Normal file
After Width: | Height: | Size: 813 B |
BIN
app/src/main/res/drawable-mdpi/ic_add.png
Normal file
After Width: | Height: | Size: 152 B |
BIN
app/src/main/res/drawable-mdpi/ic_create_new_folder_dark.png
Normal file
After Width: | Height: | Size: 242 B |
BIN
app/src/main/res/drawable-mdpi/ic_format_size_dark.png
Normal file
After Width: | Height: | Size: 155 B |
After Width: | Height: | Size: 129 B |
After Width: | Height: | Size: 138 B |
BIN
app/src/main/res/drawable-mdpi/ic_list_white_24dp.png
Normal file
After Width: | Height: | Size: 86 B |
BIN
app/src/main/res/drawable-mdpi/ic_reorder.png
Normal file
After Width: | Height: | Size: 131 B |
BIN
app/src/main/res/drawable-mdpi/ic_stat_name.png
Normal file
After Width: | Height: | Size: 643 B |
BIN
app/src/main/res/drawable-xhdpi-v11/ic_stat_name.png
Normal file
After Width: | Height: | Size: 351 B |
BIN
app/src/main/res/drawable-xhdpi-v9/ic_stat_name.png
Normal file
After Width: | Height: | Size: 496 B |
BIN
app/src/main/res/drawable-xhdpi/ic_access_alarm.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
app/src/main/res/drawable-xhdpi/ic_add.png
Normal file
After Width: | Height: | Size: 197 B |
BIN
app/src/main/res/drawable-xhdpi/ic_create_new_folder_dark.png
Normal file
After Width: | Height: | Size: 376 B |
BIN
app/src/main/res/drawable-xhdpi/ic_format_size_dark.png
Normal file
After Width: | Height: | Size: 206 B |
After Width: | Height: | Size: 164 B |
After Width: | Height: | Size: 163 B |
BIN
app/src/main/res/drawable-xhdpi/ic_list_white_24dp.png
Normal file
After Width: | Height: | Size: 95 B |
BIN
app/src/main/res/drawable-xhdpi/ic_reorder.png
Normal file
After Width: | Height: | Size: 162 B |
BIN
app/src/main/res/drawable-xhdpi/ic_stat_name.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
app/src/main/res/drawable-xxhdpi-v11/ic_stat_name.png
Normal file
After Width: | Height: | Size: 503 B |
BIN
app/src/main/res/drawable-xxhdpi-v9/ic_stat_name.png
Normal file
After Width: | Height: | Size: 620 B |
BIN
app/src/main/res/drawable-xxhdpi/ic_access_alarm.png
Normal file
After Width: | Height: | Size: 2.5 KiB |
BIN
app/src/main/res/drawable-xxhdpi/ic_add.png
Normal file
After Width: | Height: | Size: 351 B |
BIN
app/src/main/res/drawable-xxhdpi/ic_create_new_folder_dark.png
Normal file
After Width: | Height: | Size: 611 B |
BIN
app/src/main/res/drawable-xxhdpi/ic_format_size_dark.png
Normal file
After Width: | Height: | Size: 320 B |
After Width: | Height: | Size: 226 B |
After Width: | Height: | Size: 227 B |
BIN
app/src/main/res/drawable-xxhdpi/ic_list_white_24dp.png
Normal file
After Width: | Height: | Size: 94 B |
BIN
app/src/main/res/drawable-xxhdpi/ic_reorder.png
Normal file
After Width: | Height: | Size: 237 B |
BIN
app/src/main/res/drawable-xxhdpi/ic_stat_name.png
Normal file
After Width: | Height: | Size: 437 B |
After Width: | Height: | Size: 203 B |
After Width: | Height: | Size: 233 B |
BIN
app/src/main/res/drawable-xxxhdpi/ic_list_white_24dp.png
Normal file
After Width: | Height: | Size: 100 B |
6
app/src/main/res/drawable/task_select.xml
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="@android:color/holo_red_light" android:state_selected="true" />
|
||||
<item android:drawable="@android:color/holo_red_light" android:state_pressed="true" />
|
||||
<item android:drawable="@android:color/white" android:state_selected="false" />
|
||||
</selector>
|
4
app/src/main/res/drawable/tasklist_select.xml
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="@android:color/background_light" />
|
||||
</selector>
|
60
app/src/main/res/layout-w600dp/fragment_main.xml
Normal file
@@ -0,0 +1,60 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context="com.wismna.geoffroy.donext.fragments.MainFragment">
|
||||
|
||||
<android.support.design.widget.AppBarLayout
|
||||
android:id="@+id/appbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:theme="@style/AppTheme.AppBarOverlay">
|
||||
<include layout="@layout/toolbar" android:id="@+id/toolbar" />
|
||||
</android.support.design.widget.AppBarLayout>
|
||||
|
||||
<android.support.constraint.ConstraintLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginTop="?attr/actionBarSize">
|
||||
<android.support.constraint.Guideline
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/left_guideline"
|
||||
app:layout_constraintGuide_percent="0"
|
||||
android:orientation="vertical"/>
|
||||
<android.support.constraint.Guideline
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/center_guideline"
|
||||
app:layout_constraintGuide_percent=".20"
|
||||
android:orientation="vertical"/>
|
||||
<android.support.constraint.Guideline
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/right_guideline"
|
||||
app:layout_constraintGuide_percent="1"
|
||||
android:orientation="vertical"/>
|
||||
<android.widget.ListView
|
||||
android:id="@+id/list"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="0dp"
|
||||
android:choiceMode="singleChoice"
|
||||
android:listSelector="@drawable/tasklist_select"
|
||||
app:layout_constraintLeft_toRightOf="@+id/left_guideline"
|
||||
app:layout_constraintRight_toLeftOf="@+id/center_guideline" />
|
||||
<com.wismna.geoffroy.donext.widgets.NonSwipeableViewPager
|
||||
android:id="@+id/container"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_width="0dp"
|
||||
android:layout_toEndOf="@id/list"
|
||||
android:background="@android:color/background_light"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
||||
app:layout_constraintLeft_toRightOf="@+id/center_guideline"
|
||||
app:layout_constraintRight_toLeftOf="@+id/right_guideline" />
|
||||
</android.support.constraint.ConstraintLayout>
|
||||
|
||||
</android.support.design.widget.CoordinatorLayout>
|
27
app/src/main/res/layout/activity_about.xml
Normal file
@@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<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:paddingBottom="@dimen/activity_vertical_margin"
|
||||
android:paddingLeft="@dimen/activity_horizontal_margin"
|
||||
android:paddingRight="@dimen/activity_horizontal_margin"
|
||||
android:paddingTop="@dimen/activity_vertical_margin"
|
||||
android:orientation="vertical"
|
||||
tools:context=".activities.AboutActivity">
|
||||
<TextView
|
||||
android:id="@+id/version_donext"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
<TextView
|
||||
android:id="@+id/version_android"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
<TextView
|
||||
android:id="@+id/about_link"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="20dp"
|
||||
android:text="@string/about_link"
|
||||
android:autoLink="web" />
|
||||
</LinearLayout>
|
26
app/src/main/res/layout/activity_main.xml
Normal file
@@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/main_content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fitsSystemWindows="true"
|
||||
tools:context=".activities.MainActivity">
|
||||
|
||||
<fragment
|
||||
android:id="@+id/fragment_main"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:name="com.wismna.geoffroy.donext.fragments.MainFragment"
|
||||
/>
|
||||
|
||||
<android.support.design.widget.FloatingActionButton
|
||||
android:id="@+id/fab"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="end|bottom"
|
||||
android:layout_margin="@dimen/fab_margin"
|
||||
android:onClick="onNewTaskClick"
|
||||
android:src="@drawable/ic_add" />
|
||||
|
||||
</android.support.design.widget.CoordinatorLayout>
|
14
app/src/main/res/layout/activity_tasklists.xml
Normal file
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<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"
|
||||
tools:context=".activities.TaskListActivity">
|
||||
<fragment
|
||||
android:name="com.wismna.geoffroy.donext.fragments.TaskListsFragment"
|
||||
android:id="@+id/fragment_task_list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:layout="@layout/fragment_tasklists" />
|
||||
</LinearLayout>
|
35
app/src/main/res/layout/activity_today.xml
Normal file
@@ -0,0 +1,35 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fitsSystemWindows="true"
|
||||
tools:context=".activities.TodayActivity">
|
||||
|
||||
<android.support.design.widget.AppBarLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:theme="@style/AppTheme.AppBarOverlay">
|
||||
<include layout="@layout/toolbar" android:id="@+id/toolbar" />
|
||||
|
||||
</android.support.design.widget.AppBarLayout>
|
||||
|
||||
<fragment
|
||||
android:name="com.wismna.geoffroy.donext.fragments.TasksFragment"
|
||||
android:id="@+id/fragment_task_list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
||||
tools:layout="@layout/fragment_tasks" />
|
||||
|
||||
<android.support.design.widget.FloatingActionButton
|
||||
android:id="@+id/fab"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="end|bottom"
|
||||
android:layout_margin="@dimen/fab_margin"
|
||||
android:onClick="onNewTaskClick"
|
||||
android:src="@drawable/ic_add" />
|
||||
|
||||
</android.support.design.widget.CoordinatorLayout>
|
120
app/src/main/res/layout/content_task_form.xml
Normal file
@@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ScrollView
|
||||
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="@android:color/background_light">
|
||||
<RelativeLayout
|
||||
android:id="@+id/new_task_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="@dimen/text_margin"
|
||||
android:orientation="vertical"
|
||||
android:focusable="true"
|
||||
android:focusableInTouchMode="true"
|
||||
tools:context=".activities.MainActivity">
|
||||
<TextView
|
||||
android:id="@+id/new_task_list_label"
|
||||
android:text="@string/new_task_list"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:layout_marginTop="3dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
<Spinner
|
||||
android:id="@+id/new_task_list"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="5dp"
|
||||
android:layout_toEndOf="@id/new_task_list_label">
|
||||
</Spinner>
|
||||
<EditText
|
||||
android:id="@+id/new_task_name"
|
||||
android:hint="@string/new_task_name_hint"
|
||||
android:maxLines="1"
|
||||
android:inputType="text"
|
||||
android:textSize="30sp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/new_task_list"
|
||||
android:imeOptions="flagNoFullscreen"/>
|
||||
<EditText
|
||||
android:id="@+id/new_task_description"
|
||||
android:hint="@string/new_task_description_hint"
|
||||
android:gravity="top|start"
|
||||
android:lines="3"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/new_task_name"
|
||||
android:imeOptions="flagNoFullscreen" />
|
||||
<TextView
|
||||
android:id="@+id/new_task_priority_label"
|
||||
android:text="@string/new_task_priority"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:layout_below="@id/new_task_description" />
|
||||
<SeekBar
|
||||
android:id="@+id/new_task_priority"
|
||||
android:max="2"
|
||||
android:progress="1"
|
||||
android:layout_width="300dp"
|
||||
android:layout_height="30dp"
|
||||
android:layout_toEndOf="@id/new_task_priority_label"
|
||||
android:layout_below="@id/new_task_description" />
|
||||
<TextView
|
||||
android:id="@+id/new_task_priority_tooltip"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:layout_width="80dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:padding="10dp"
|
||||
android:layout_above="@id/new_task_priority"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:background="@android:color/darker_gray"
|
||||
android:textColor="@android:color/white"
|
||||
android:textAlignment="center"
|
||||
android:visibility="gone" />
|
||||
<CheckBox
|
||||
android:id="@+id/new_task_today"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="visible"
|
||||
android:layout_below="@id/new_task_priority"
|
||||
android:layout_alignParentEnd="true" />
|
||||
<TextView
|
||||
android:id="@+id/new_task_today_label"
|
||||
android:text="@string/new_task_today"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:visibility="visible"
|
||||
android:layout_below="@id/new_task_priority" />
|
||||
<CheckBox
|
||||
android:id="@+id/new_task_due_date_set"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/new_task_today"
|
||||
android:layout_alignParentEnd="true" />
|
||||
<TextView
|
||||
android:id="@+id/new_task_due_date_label"
|
||||
android:text="@string/new_task_due_date"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_below="@id/new_task_today" />
|
||||
<DatePicker
|
||||
android:id="@+id/new_task_due_date"
|
||||
android:datePickerMode="spinner"
|
||||
android:calendarViewShown="false"
|
||||
android:spinnersShown="true"
|
||||
android:visibility="gone"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/new_task_due_date_label" />
|
||||
</RelativeLayout>
|
||||
</ScrollView>
|
27
app/src/main/res/layout/content_today_form.xml
Normal file
@@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:focusable="true"
|
||||
android:focusableInTouchMode="true"
|
||||
android:background="@android:color/background_light" >
|
||||
<EditText
|
||||
android:id="@+id/today_search"
|
||||
android:hint="@string/today_search_hint"
|
||||
android:maxLines="1"
|
||||
android:inputType="text"
|
||||
android:textSize="30sp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:imeOptions="flagNoFullscreen" />
|
||||
<ListView
|
||||
android:id="@+id/today_tasks"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:textFilterEnabled="true"
|
||||
android:drawSelectorOnTop="true"
|
||||
android:choiceMode="multipleChoice">
|
||||
|
||||
</ListView>
|
||||
</LinearLayout>
|
25
app/src/main/res/layout/fragment_dynamic_dialog.xml
Normal file
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fitsSystemWindows="true">
|
||||
|
||||
<android.support.design.widget.AppBarLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:theme="@style/AppTheme.AppBarOverlay">
|
||||
<include layout="@layout/toolbar" android:id="@+id/dialog_toolbar" />
|
||||
</android.support.design.widget.AppBarLayout>
|
||||
<!-- This will contain the actual contents of the dialog -->
|
||||
<FrameLayout
|
||||
android:id="@+id/dynamic_fragment_content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginTop="?attr/actionBarSize" >
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/incompatible_sdk_version"/>
|
||||
</FrameLayout>
|
||||
|
||||
</android.support.design.widget.CoordinatorLayout>
|
51
app/src/main/res/layout/fragment_main.xml
Normal file
@@ -0,0 +1,51 @@
|
||||
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context="com.wismna.geoffroy.donext.fragments.MainFragment">
|
||||
|
||||
<android.support.design.widget.AppBarLayout
|
||||
android:id="@+id/appbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="@dimen/appbar_padding_top"
|
||||
android:theme="@style/AppTheme.AppBarOverlay">
|
||||
<include layout="@layout/toolbar" android:id="@+id/toolbar" />
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
<ImageView
|
||||
android:id="@+id/left_arrow"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:contentDescription="@string/tab_left_arrow"
|
||||
android:src="@drawable/ic_keyboard_arrow_left_white_24dp" />
|
||||
<ImageView
|
||||
android:id="@+id/right_arrow"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:contentDescription="@string/tab_right_arrow"
|
||||
android:src="@drawable/ic_keyboard_arrow_right_white_24dp" />
|
||||
<android.support.design.widget.TabLayout
|
||||
android:id="@+id/tabs"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_toEndOf="@+id/left_arrow"
|
||||
android:layout_toStartOf="@+id/right_arrow"
|
||||
app:tabMode="scrollable" />
|
||||
</RelativeLayout>
|
||||
</android.support.design.widget.AppBarLayout>
|
||||
|
||||
<com.wismna.geoffroy.donext.widgets.NonSwipeableViewPager
|
||||
android:id="@+id/container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
|
||||
|
||||
</android.support.design.widget.CoordinatorLayout>
|
13
app/src/main/res/layout/fragment_task_confirmation.xml
Normal file
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
<CheckBox
|
||||
android:id="@+id/task_confirmation_never"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/text_margin"
|
||||
android:layout_marginTop="10dp"
|
||||
android:text="@string/task_confirmation_never_button" />
|
||||
</LinearLayout>
|
45
app/src/main/res/layout/fragment_task_detailed.xml
Normal file
@@ -0,0 +1,45 @@
|
||||
<?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="70dp"
|
||||
android:paddingTop="5dp"
|
||||
android:orientation="horizontal"
|
||||
android:focusable="true"
|
||||
android:background="?android:attr/selectableItemBackground" >
|
||||
<TextView
|
||||
android:id="@+id/task_cycle"
|
||||
android:layout_width="30dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="10dp"
|
||||
android:textAppearance="?attr/textAppearanceListItem" />
|
||||
<TextView
|
||||
android:id="@+id/task_id"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone" />
|
||||
<ImageView
|
||||
android:id="@+id/task_alarm"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="10dp"
|
||||
android:layout_marginEnd="5dp"
|
||||
android:contentDescription="@string/task_alarm"/>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="?listPreferredItemHeight"
|
||||
android:orientation="vertical">
|
||||
<TextView
|
||||
android:id="@+id/task_name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?attr/textAppearanceListItem" />
|
||||
<TextView
|
||||
android:id="@+id/task_description"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:maxLines="2"
|
||||
android:textColor="@color/colorPrimary"
|
||||
android:textSize="14sp"
|
||||
android:textAppearance="?attr/textAppearanceListItemSmall" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
34
app/src/main/res/layout/fragment_task_simple.xml
Normal file
@@ -0,0 +1,34 @@
|
||||
<?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="70dp"
|
||||
android:orientation="horizontal"
|
||||
android:background="?android:attr/selectableItemBackground" >
|
||||
<TextView
|
||||
android:id="@+id/task_cycle"
|
||||
android:layout_width="30dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="15dp"
|
||||
android:paddingTop="10dp"
|
||||
android:textAppearance="?attr/textAppearanceListItem" />
|
||||
<TextView
|
||||
android:id="@+id/task_id"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone" />
|
||||
<ImageView
|
||||
android:id="@+id/task_alarm"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="10dp"
|
||||
android:layout_marginEnd="5dp"
|
||||
android:layout_marginTop="10dp"
|
||||
android:contentDescription="@string/task_alarm"/>
|
||||
<TextView
|
||||
android:id="@+id/task_name"
|
||||
android:layout_marginTop="15dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?attr/textAppearanceListItem"
|
||||
android:textSize="25sp"/>
|
||||
</LinearLayout>
|
34
app/src/main/res/layout/fragment_tasklist.xml
Normal file
@@ -0,0 +1,34 @@
|
||||
<?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">
|
||||
<ImageView
|
||||
android:id="@+id/handle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center_vertical|start"
|
||||
android:scaleType="center"
|
||||
android:src="@drawable/ic_reorder"
|
||||
android:contentDescription="@string/task_list_drag_handle"/>
|
||||
<TextView
|
||||
android:id="@+id/task_list_count"
|
||||
android:layout_width="50dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAlignment="center"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"/>
|
||||
<EditText
|
||||
android:id="@+id/task_list_name"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="?listPreferredItemHeight"
|
||||
android:layout_weight="2"
|
||||
android:inputType="text"
|
||||
android:hint="@string/task_list_edit_list_hint"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge"/>
|
||||
<Button
|
||||
android:id="@+id/task_list_delete"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="10dp"
|
||||
android:text="@string/task_list_delete" />
|
||||
</LinearLayout>
|
48
app/src/main/res/layout/fragment_tasklists.xml
Normal file
@@ -0,0 +1,48 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/new_task_list_parent_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:focusableInTouchMode="true"
|
||||
android:descendantFocusability="beforeDescendants"
|
||||
android:paddingBottom="@dimen/activity_vertical_margin"
|
||||
android:paddingLeft="@dimen/activity_horizontal_margin"
|
||||
android:paddingRight="@dimen/activity_horizontal_margin"
|
||||
android:paddingTop="@dimen/activity_vertical_margin"
|
||||
android:orientation="vertical"
|
||||
tools:context=".activities.TaskListActivity">
|
||||
<LinearLayout
|
||||
android:id="@+id/new_task_list_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="75dp">
|
||||
<EditText
|
||||
android:id="@+id/new_task_list_name"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="2"
|
||||
android:hint="@string/task_list_new_list_hint"
|
||||
android:maxLines="1"
|
||||
android:inputType="text" />
|
||||
<Button
|
||||
android:id="@+id/new_task_list_button"
|
||||
android:layout_width="80dp"
|
||||
android:layout_height="wrap_content"
|
||||
style="@style/Widget.AppCompat.Button.Colored"
|
||||
android:text="@string/task_list_new_list_create"/>
|
||||
</LinearLayout>
|
||||
<android.support.v7.widget.RecyclerView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/task_lists_view"
|
||||
android:name="com.wismna.geoffroy.donext.fragments.TaskListFragment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:layoutManager="LinearLayoutManager"
|
||||
tools:context=".fragments.TaskListsFragment"
|
||||
tools:listitem="@layout/fragment_tasklist" />
|
||||
</LinearLayout>
|
||||
|
||||
|
74
app/src/main/res/layout/fragment_tasks.xml
Normal file
@@ -0,0 +1,74 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@drawable/task_select" >
|
||||
<TextView
|
||||
android:id="@+id/total_task_cycles"
|
||||
android:layout_width="100dp"
|
||||
android:layout_height="wrap_content"/>
|
||||
<TextView
|
||||
android:id="@+id/total_task_count"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="top|center"/>
|
||||
<TextView
|
||||
android:id="@+id/no_more_tasks"
|
||||
android:text="@string/task_no_tasks"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center|center"
|
||||
android:visibility="gone"/>
|
||||
<android.support.v7.widget.RecyclerView
|
||||
android:id="@+id/task_list_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginStart="5dp"
|
||||
android:layout_marginEnd="5dp"
|
||||
android:layout_marginTop="15dp"
|
||||
android:layout_marginBottom="15dp"
|
||||
android:name="com.wismna.geoffroy.donext.activities.TaskFragment"
|
||||
app:layoutManager="LinearLayoutManager"
|
||||
tools:context=".fragments.TasksFragment"
|
||||
tools:listitem="@layout/fragment_task_detailed" />
|
||||
<RelativeLayout
|
||||
android:id="@+id/task_list_background"
|
||||
android:layout_marginLeft="@dimen/text_margin"
|
||||
android:layout_marginRight="@dimen/text_margin"
|
||||
android:layout_height="70dp"
|
||||
android:layout_width="match_parent"
|
||||
android:background="@color/colorAccent"
|
||||
android:visibility="gone">
|
||||
<TextView
|
||||
android:id="@+id/task_background_done"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:text="@string/task_confirmation_done_button"
|
||||
android:textAllCaps="true"
|
||||
android:textSize="20sp"
|
||||
android:textColor="@android:color/white"
|
||||
android:visibility="gone"/>
|
||||
<TextView
|
||||
android:id="@+id/task_background_next"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:text="@string/task_confirmation_next_button"
|
||||
android:textAllCaps="true"
|
||||
android:textSize="20sp"
|
||||
android:textColor="@android:color/white"
|
||||
android:visibility="gone"/>
|
||||
</RelativeLayout>
|
||||
<TextView
|
||||
android:id="@+id/remaining_task_count"
|
||||
android:layout_width="150dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom|center"/>
|
||||
</FrameLayout>
|
22
app/src/main/res/layout/list_task_item.xml
Normal file
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/task_list_item_layout"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="match_parent"
|
||||
android:orientation="vertical">
|
||||
<TextView
|
||||
android:id="@+id/task_list_item_tasklist"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:textColor="@color/colorPrimaryDark"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="4dp" />
|
||||
<TextView
|
||||
android:id="@+id/task_list_item_title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="20sp"
|
||||
android:layout_marginStart="20dp"
|
||||
android:layout_marginBottom="4dp"/>
|
||||
</LinearLayout>
|
7
app/src/main/res/layout/list_tasklist_item.xml
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<TextView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:padding="15dp"
|
||||
android:textSize="15sp" />
|