mirror of https://github.com/tasks/tasks
Initial support for creating tasks via Tasker
parent
169c7564d5
commit
b5d9722220
@ -0,0 +1,218 @@
|
|||||||
|
//package com.yourcompany.yourcondition;
|
||||||
|
//package com.yourcompany.yoursetting;
|
||||||
|
package net.dinglisch.android.tasker;
|
||||||
|
|
||||||
|
// Constants and functions for Tasker *extensions* to the plugin protocol
|
||||||
|
// See Also: http://tasker.dinglisch.net/plugins.html
|
||||||
|
|
||||||
|
// Release Notes
|
||||||
|
|
||||||
|
// v1.1 20140202
|
||||||
|
// added function variableNameValid()
|
||||||
|
// fixed some javadoc entries (thanks to David Stone)
|
||||||
|
|
||||||
|
// v1.2 20140211
|
||||||
|
// added ACTION_EDIT_EVENT
|
||||||
|
|
||||||
|
// v1.3 20140227
|
||||||
|
// added REQUESTED_TIMEOUT_MS_NONE, REQUESTED_TIMEOUT_MS_MAX and REQUESTED_TIMEOUT_MS_NEVER
|
||||||
|
// requestTimeoutMS(): added range check
|
||||||
|
|
||||||
|
// v1.4 20140516
|
||||||
|
// support for data pass through in REQUEST_QUERY intent
|
||||||
|
// some javadoc entries fixed (thanks again David :-))
|
||||||
|
|
||||||
|
// v1.5 20141120
|
||||||
|
// added RESULT_CODE_FAILED_PLUGIN_FIRST
|
||||||
|
// added Setting.VARNAME_ERROR_MESSAGE
|
||||||
|
|
||||||
|
// v1.6 20150213
|
||||||
|
// added Setting.getHintTimeoutMS()
|
||||||
|
// added Host.addHintTimeoutMS()
|
||||||
|
|
||||||
|
// v1.7 20160619
|
||||||
|
// null check for getCallingActivity() in hostSupportsOnFireVariableReplacement( Activity editActivity )
|
||||||
|
|
||||||
|
// v1.8 20161002
|
||||||
|
// added hostSupportsKeyEncoding(), setKeyEncoding() and Host.getKeysWithEncoding()
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.content.ComponentName;
|
||||||
|
import android.content.pm.PackageInfo;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
public class TaskerPlugin {
|
||||||
|
|
||||||
|
private final static String TAG = "TaskerPlugin";
|
||||||
|
|
||||||
|
private final static String BASE_KEY = "net.dinglisch.android.tasker";
|
||||||
|
|
||||||
|
private final static String EXTRAS_PREFIX = BASE_KEY + ".extras.";
|
||||||
|
|
||||||
|
private final static int FIRST_ON_FIRE_VARIABLES_TASKER_VERSION = 80;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Host capabilities, passed to plugin with edit intents
|
||||||
|
*/
|
||||||
|
private final static String EXTRA_HOST_CAPABILITIES = EXTRAS_PREFIX + "HOST_CAPABILITIES";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see Setting#hostSupportsOnFireVariableReplacement(Bundle)
|
||||||
|
*/
|
||||||
|
public final static int EXTRA_HOST_CAPABILITY_SETTING_FIRE_VARIABLE_REPLACEMENT = 8;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Possible encodings of text in bundle values
|
||||||
|
*
|
||||||
|
* @see #setKeyEncoding(Bundle,String[],Encoding)
|
||||||
|
*/
|
||||||
|
public enum Encoding { JSON };
|
||||||
|
|
||||||
|
// ----------------------------- SETTING PLUGIN ONLY --------------------------------- //
|
||||||
|
|
||||||
|
public static class Setting {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see #setVariableReplaceKeys(Bundle, String[])
|
||||||
|
*/
|
||||||
|
private final static String BUNDLE_KEY_VARIABLE_REPLACE_STRINGS = EXTRAS_PREFIX + "VARIABLE_REPLACE_KEYS";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used by: plugin EditActivity.
|
||||||
|
*
|
||||||
|
* Indicates to plugin that host will replace variables in specified bundle keys.
|
||||||
|
*
|
||||||
|
* Replacement takes place every time the setting is fired, before the bundle is
|
||||||
|
* passed to the plugin FireReceiver.
|
||||||
|
*
|
||||||
|
* @param extrasFromHost intent extras from the intent received by the edit activity
|
||||||
|
* @see #setVariableReplaceKeys(Bundle, String[])
|
||||||
|
*/
|
||||||
|
public static boolean hostSupportsOnFireVariableReplacement( Bundle extrasFromHost ) {
|
||||||
|
return hostSupports( extrasFromHost, EXTRA_HOST_CAPABILITY_SETTING_FIRE_VARIABLE_REPLACEMENT );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used by: plugin EditActivity.
|
||||||
|
*
|
||||||
|
* Description as above.
|
||||||
|
*
|
||||||
|
* This version also includes backwards compatibility with pre 4.2 Tasker versions.
|
||||||
|
* At some point this function will be deprecated.
|
||||||
|
*
|
||||||
|
* @param editActivity the plugin edit activity, needed to test calling Tasker version
|
||||||
|
* @see #setVariableReplaceKeys(Bundle, String[])
|
||||||
|
*/
|
||||||
|
|
||||||
|
public static boolean hostSupportsOnFireVariableReplacement( Activity editActivity ) {
|
||||||
|
|
||||||
|
boolean supportedFlag = hostSupportsOnFireVariableReplacement( editActivity.getIntent().getExtras() );
|
||||||
|
|
||||||
|
if ( ! supportedFlag ) {
|
||||||
|
|
||||||
|
ComponentName callingActivity = editActivity.getCallingActivity();
|
||||||
|
|
||||||
|
if ( callingActivity == null )
|
||||||
|
Log.w( TAG, "hostSupportsOnFireVariableReplacement: null callingActivity, defaulting to false" );
|
||||||
|
else {
|
||||||
|
String callerPackage = callingActivity.getPackageName();
|
||||||
|
|
||||||
|
// Tasker only supporteed this from 1.0.10
|
||||||
|
supportedFlag =
|
||||||
|
( callerPackage.startsWith( BASE_KEY ) ) &&
|
||||||
|
( getPackageVersionCode( editActivity.getPackageManager(), callerPackage ) > FIRST_ON_FIRE_VARIABLES_TASKER_VERSION )
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return supportedFlag;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used by: plugin EditActivity
|
||||||
|
*
|
||||||
|
* Indicates to host which bundle keys should be replaced.
|
||||||
|
*
|
||||||
|
* @param resultBundleToHost the bundle being returned to the host
|
||||||
|
* @param listOfKeyNames which bundle keys to replace variables in when setting fires
|
||||||
|
* @see #hostSupportsOnFireVariableReplacement(Bundle)
|
||||||
|
* @see #setKeyEncoding(Bundle,String[],Encoding)
|
||||||
|
*/
|
||||||
|
public static void setVariableReplaceKeys( Bundle resultBundleToHost, String [] listOfKeyNames ) {
|
||||||
|
addStringArrayToBundleAsString(
|
||||||
|
listOfKeyNames, resultBundleToHost, BUNDLE_KEY_VARIABLE_REPLACE_STRINGS,
|
||||||
|
"setVariableReplaceKeys"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------- HELPER FUNCTIONS -------------------------------- //
|
||||||
|
|
||||||
|
private static Object getBundleValueSafe( Bundle b, String key, Class<?> expectedClass, String funcName ) {
|
||||||
|
Object value = null;
|
||||||
|
|
||||||
|
if ( b != null ) {
|
||||||
|
if ( b.containsKey( key ) ) {
|
||||||
|
Object obj = b.get( key );
|
||||||
|
if ( obj == null )
|
||||||
|
Log.w( TAG, funcName + ": " + key + ": null value" );
|
||||||
|
else if ( obj.getClass() != expectedClass )
|
||||||
|
Log.w( TAG, funcName + ": " + key + ": expected " + expectedClass.getClass().getName() + ", got " + obj.getClass().getName() );
|
||||||
|
else
|
||||||
|
value = obj;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean hostSupports( Bundle extrasFromHost, int capabilityFlag ) {
|
||||||
|
Integer flags = (Integer) getBundleValueSafe( extrasFromHost, EXTRA_HOST_CAPABILITIES, Integer.class, "hostSupports" );
|
||||||
|
return
|
||||||
|
( flags != null ) &&
|
||||||
|
( ( flags & capabilityFlag ) > 0 )
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getPackageVersionCode( PackageManager pm, String packageName ) {
|
||||||
|
|
||||||
|
int code = -1;
|
||||||
|
|
||||||
|
if ( pm != null ) {
|
||||||
|
try {
|
||||||
|
PackageInfo pi = pm.getPackageInfo( packageName, 0 );
|
||||||
|
if ( pi != null )
|
||||||
|
code = pi.versionCode;
|
||||||
|
}
|
||||||
|
catch ( Exception e ) {
|
||||||
|
Log.e( TAG, "getPackageVersionCode: exception getting package info" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void addStringArrayToBundleAsString( String [] toAdd, Bundle bundle, String key, String callerName ) {
|
||||||
|
|
||||||
|
StringBuilder builder = new StringBuilder();
|
||||||
|
|
||||||
|
if ( toAdd != null ) {
|
||||||
|
|
||||||
|
for ( String keyName : toAdd ) {
|
||||||
|
|
||||||
|
if ( keyName.contains( " " ) )
|
||||||
|
Log.w( TAG, callerName + ": ignoring bad keyName containing space: " + keyName );
|
||||||
|
else {
|
||||||
|
if ( builder.length() > 0 )
|
||||||
|
builder.append( ' ' );
|
||||||
|
|
||||||
|
builder.append( keyName );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( builder.length() > 0 )
|
||||||
|
bundle.putString( key, builder.toString() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,87 @@
|
|||||||
|
package org.tasks.locale.bundle;
|
||||||
|
|
||||||
|
import android.os.Bundle;
|
||||||
|
|
||||||
|
import org.tasks.BuildConfig;
|
||||||
|
|
||||||
|
public class TaskCreationBundle {
|
||||||
|
|
||||||
|
public static final String EXTRA_BUNDLE = "org.tasks.locale.create";
|
||||||
|
public static final String EXTRA_TITLE = "org.tasks.locale.create.STRING_TITLE";
|
||||||
|
public static final String EXTRA_DUE_DATE = "org.tasks.locale.create.STRING_DUE_DATE";
|
||||||
|
public static final String EXTRA_DUE_TIME = "org.tasks.locale.create.STRING_DUE_TIME";
|
||||||
|
public static final String EXTRA_PRIORITY = "org.tasks.locale.create.STRING_PRIORITY";
|
||||||
|
public static final String EXTRA_DESCRIPTION = "org.tasks.locale.create.STRING_DESCRIPTION";
|
||||||
|
public static final String EXTRA_VERSION_CODE = "org.tasks.locale.create.INT_VERSION_CODE";
|
||||||
|
|
||||||
|
private final Bundle bundle;
|
||||||
|
|
||||||
|
public TaskCreationBundle() {
|
||||||
|
this(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TaskCreationBundle(Bundle bundle) {
|
||||||
|
if (bundle == null) {
|
||||||
|
this.bundle = new Bundle();
|
||||||
|
this.bundle.putInt(EXTRA_VERSION_CODE, BuildConfig.VERSION_CODE);
|
||||||
|
} else {
|
||||||
|
this.bundle = bundle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isBundleValid(Bundle bundle) {
|
||||||
|
return -1 != bundle.getInt(EXTRA_VERSION_CODE, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTitle(String title) {
|
||||||
|
bundle.putString(EXTRA_TITLE, title);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTitle() {
|
||||||
|
return bundle.getString(EXTRA_TITLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDueDate(String dueDate) {
|
||||||
|
bundle.putString(EXTRA_DUE_DATE, dueDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDueDate() {
|
||||||
|
return bundle.getString(EXTRA_DUE_DATE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDueTime(String dueTime) {
|
||||||
|
bundle.putString(EXTRA_DUE_TIME, dueTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDueTime() {
|
||||||
|
return bundle.getString(EXTRA_DUE_TIME);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPriority(String priority) {
|
||||||
|
bundle.putString(EXTRA_PRIORITY, priority);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPriority() {
|
||||||
|
return bundle.getString(EXTRA_PRIORITY);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDescription(String description) {
|
||||||
|
bundle.putString(EXTRA_DESCRIPTION, description);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription() {
|
||||||
|
return bundle.getString(EXTRA_DESCRIPTION);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Bundle build() {
|
||||||
|
bundle.putInt(EXTRA_VERSION_CODE, BuildConfig.VERSION_CODE);
|
||||||
|
return bundle;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "TaskCreationBundle{" +
|
||||||
|
"bundle=" + bundle +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,62 @@
|
|||||||
|
package org.tasks.locale.receiver;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
|
||||||
|
import com.todoroo.astrid.api.Filter;
|
||||||
|
|
||||||
|
import org.tasks.Notifier;
|
||||||
|
import org.tasks.analytics.Tracker;
|
||||||
|
import org.tasks.analytics.Tracking;
|
||||||
|
import org.tasks.injection.ForApplication;
|
||||||
|
import org.tasks.injection.InjectingJobIntentService;
|
||||||
|
import org.tasks.injection.IntentServiceComponent;
|
||||||
|
import org.tasks.locale.bundle.ListNotificationBundle;
|
||||||
|
import org.tasks.locale.bundle.TaskCreationBundle;
|
||||||
|
import org.tasks.preferences.DefaultFilterProvider;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import timber.log.Timber;
|
||||||
|
|
||||||
|
public class TaskerIntentService extends InjectingJobIntentService {
|
||||||
|
|
||||||
|
@Inject @ForApplication Context context;
|
||||||
|
@Inject Notifier notifier;
|
||||||
|
@Inject DefaultFilterProvider defaultFilterProvider;
|
||||||
|
@Inject TaskerTaskCreator taskerTaskCreator;
|
||||||
|
@Inject Tracker tracker;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onHandleWork(@NonNull Intent intent) {
|
||||||
|
super.onHandleWork(intent);
|
||||||
|
|
||||||
|
final Bundle bundle = intent
|
||||||
|
.getBundleExtra(com.twofortyfouram.locale.api.Intent.EXTRA_BUNDLE);
|
||||||
|
|
||||||
|
if (null == bundle) {
|
||||||
|
Timber.e("%s is missing",
|
||||||
|
com.twofortyfouram.locale.api.Intent.EXTRA_BUNDLE); //$NON-NLS-1$
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ListNotificationBundle.isBundleValid(bundle)) {
|
||||||
|
Filter filter = defaultFilterProvider.getFilterFromPreference(
|
||||||
|
bundle.getString(ListNotificationBundle.BUNDLE_EXTRA_STRING_FILTER));
|
||||||
|
notifier.triggerFilterNotification(filter);
|
||||||
|
tracker.reportEvent(Tracking.Events.TASKER_LIST_NOTIFICATION);
|
||||||
|
} else if (TaskCreationBundle.isBundleValid(bundle)) {
|
||||||
|
taskerTaskCreator.handle(new TaskCreationBundle(bundle));
|
||||||
|
tracker.reportEvent(Tracking.Events.TASKER_CREATE);
|
||||||
|
} else {
|
||||||
|
Timber.e("Invalid bundle: %s", bundle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void inject(IntentServiceComponent component) {
|
||||||
|
component.inject(this);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,76 @@
|
|||||||
|
package org.tasks.locale.receiver;
|
||||||
|
|
||||||
|
import com.todoroo.astrid.dao.TaskDao;
|
||||||
|
import com.todoroo.astrid.data.Task;
|
||||||
|
import com.todoroo.astrid.service.TaskCreator;
|
||||||
|
|
||||||
|
import org.tasks.locale.bundle.TaskCreationBundle;
|
||||||
|
import org.tasks.time.DateTime;
|
||||||
|
import org.threeten.bp.LocalDate;
|
||||||
|
import org.threeten.bp.LocalTime;
|
||||||
|
import org.threeten.bp.format.DateTimeFormatter;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import timber.log.Timber;
|
||||||
|
|
||||||
|
import static com.google.common.base.Strings.isNullOrEmpty;
|
||||||
|
import static org.tasks.time.DateTimeUtils.currentTimeMillis;
|
||||||
|
|
||||||
|
public class TaskerTaskCreator {
|
||||||
|
|
||||||
|
private static final DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("MM-dd-yy");
|
||||||
|
private static final DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("HH.mm");
|
||||||
|
|
||||||
|
private final TaskCreator taskCreator;
|
||||||
|
private final TaskDao taskDao;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public TaskerTaskCreator(TaskCreator taskCreator, TaskDao taskDao) {
|
||||||
|
this.taskCreator = taskCreator;
|
||||||
|
this.taskDao = taskDao;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void handle(TaskCreationBundle bundle) {
|
||||||
|
Task task = taskCreator.createWithValues(null, bundle.getTitle());
|
||||||
|
|
||||||
|
String dueDateString = bundle.getDueDate();
|
||||||
|
if (!isNullOrEmpty(dueDateString)) {
|
||||||
|
try {
|
||||||
|
LocalDate dueDate = LocalDate.parse(dueDateString, dateFormatter);
|
||||||
|
DateTime dt = new DateTime(dueDate.getYear(), dueDate.getMonthValue(), dueDate.getDayOfMonth());
|
||||||
|
task.setDueDate(Task.createDueDate(Task.URGENCY_SPECIFIC_DAY, dt.getMillis()));
|
||||||
|
} catch(Exception e) {
|
||||||
|
Timber.e(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String dueTimeString = bundle.getDueTime();
|
||||||
|
if (!isNullOrEmpty(dueTimeString)) {
|
||||||
|
try {
|
||||||
|
LocalTime dueTime = LocalTime.parse(dueTimeString, timeFormatter);
|
||||||
|
task.setDueDate(Task.createDueDate(Task.URGENCY_SPECIFIC_DAY_TIME,
|
||||||
|
new DateTime(task.hasDueDate() ? task.getDueDate() : currentTimeMillis())
|
||||||
|
.withHourOfDay(dueTime.getHour())
|
||||||
|
.withMinuteOfHour(dueTime.getMinute())
|
||||||
|
.getMillis()));
|
||||||
|
} catch (Exception e) {
|
||||||
|
Timber.e(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String priorityString = bundle.getPriority();
|
||||||
|
if (!isNullOrEmpty(priorityString)) {
|
||||||
|
try {
|
||||||
|
int priority = Integer.parseInt(priorityString);
|
||||||
|
task.setImportance(Math.max(0, Math.min(3, priority)));
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
Timber.e(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
task.setNotes(bundle.getDescription());
|
||||||
|
|
||||||
|
taskDao.save(task);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,140 @@
|
|||||||
|
package org.tasks.locale.ui.activity;
|
||||||
|
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Bundle;
|
||||||
|
|
||||||
|
import org.tasks.injection.InjectingPreferenceActivity;
|
||||||
|
|
||||||
|
import timber.log.Timber;
|
||||||
|
|
||||||
|
public abstract class AbstractFragmentPluginPreferenceActivity extends InjectingPreferenceActivity {
|
||||||
|
|
||||||
|
boolean mIsCancelled = false;
|
||||||
|
|
||||||
|
/* package */ private static boolean isLocalePluginIntent(final Intent intent) {
|
||||||
|
final String action = intent.getAction();
|
||||||
|
|
||||||
|
return com.twofortyfouram.locale.api.Intent.ACTION_EDIT_CONDITION.equals(action)
|
||||||
|
|| com.twofortyfouram.locale.api.Intent.ACTION_EDIT_SETTING.equals(action);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(final Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
|
if (isLocalePluginIntent(getIntent())) {
|
||||||
|
final Bundle previousBundle = getPreviousBundle();
|
||||||
|
|
||||||
|
Timber.d("Creating Activity with Intent=%s, savedInstanceState=%s, EXTRA_BUNDLE=%s",
|
||||||
|
getIntent(), savedInstanceState, previousBundle); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPostCreate(final Bundle savedInstanceState) {
|
||||||
|
super.onPostCreate(savedInstanceState);
|
||||||
|
|
||||||
|
if (isLocalePluginIntent(getIntent())) {
|
||||||
|
if (null == savedInstanceState) {
|
||||||
|
final Bundle previousBundle = getPreviousBundle();
|
||||||
|
final String previousBlurb = getPreviousBlurb();
|
||||||
|
if (null != previousBundle && null != previousBlurb) {
|
||||||
|
onPostCreateWithPreviousResult(previousBundle, previousBlurb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void finish() {
|
||||||
|
if (isLocalePluginIntent(getIntent())) {
|
||||||
|
if (!mIsCancelled) {
|
||||||
|
final Bundle resultBundle = getResultBundle();
|
||||||
|
|
||||||
|
if (null != resultBundle) {
|
||||||
|
String blurb = getResultBlurb(resultBundle);
|
||||||
|
Intent resultIntent = new Intent();
|
||||||
|
resultIntent.putExtra(com.twofortyfouram.locale.api.Intent.EXTRA_BUNDLE,
|
||||||
|
resultBundle);
|
||||||
|
resultIntent.putExtra(com.twofortyfouram.locale.api.Intent.EXTRA_STRING_BLURB,
|
||||||
|
blurb);
|
||||||
|
setResult(RESULT_OK, resultIntent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
super.finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The {@link com.twofortyfouram.locale.api.Intent#EXTRA_BUNDLE EXTRA_BUNDLE} that was
|
||||||
|
* previously saved to the host and subsequently passed back to this Activity for further
|
||||||
|
* editing. Internally, this method relies on {@link #isBundleValid(Bundle)}. If
|
||||||
|
* the bundle exists but is not valid, this method will return null.
|
||||||
|
*/
|
||||||
|
private Bundle getPreviousBundle() {
|
||||||
|
final Bundle bundle = getIntent().getBundleExtra(
|
||||||
|
com.twofortyfouram.locale.api.Intent.EXTRA_BUNDLE);
|
||||||
|
|
||||||
|
if (null != bundle) {
|
||||||
|
if (isBundleValid(bundle)) {
|
||||||
|
return bundle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The {@link com.twofortyfouram.locale.api.Intent#EXTRA_STRING_BLURB
|
||||||
|
* EXTRA_STRING_BLURB} that was
|
||||||
|
* previously saved to the host and subsequently passed back to this Activity for further
|
||||||
|
* editing.
|
||||||
|
*/
|
||||||
|
private String getPreviousBlurb() {
|
||||||
|
return getIntent().getStringExtra(
|
||||||
|
com.twofortyfouram.locale.api.Intent.EXTRA_STRING_BLURB);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Validates the Bundle, to ensure that a malicious application isn't attempting to pass
|
||||||
|
* an invalid Bundle.</p>
|
||||||
|
*
|
||||||
|
* @param bundle The plug-in's Bundle previously returned by the edit
|
||||||
|
* Activity. {@code bundle} should not be mutated by this method.
|
||||||
|
* @return true if {@code bundle} is valid for the plug-in.
|
||||||
|
*/
|
||||||
|
protected abstract boolean isBundleValid(final Bundle bundle);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Plug-in Activity lifecycle callback to allow the Activity to restore
|
||||||
|
* state for editing a previously saved plug-in instance. This callback will
|
||||||
|
* occur during the onPostCreate() phase of the Activity lifecycle.
|
||||||
|
* <p>{@code bundle} will have been
|
||||||
|
* validated by {@link #isBundleValid(Bundle)} prior to this
|
||||||
|
* method being called. If {@link #isBundleValid(Bundle)} returned false, then this
|
||||||
|
* method will not be called. This helps ensure that plug-in Activity subclasses only have to
|
||||||
|
* worry about bundle validation once, in the {@link #isBundleValid(Bundle)}
|
||||||
|
* method.</p>
|
||||||
|
* <p>Note this callback only occurs the first time the Activity is created, so it will not be
|
||||||
|
* called
|
||||||
|
* when the Activity is recreated (e.g. {@code savedInstanceState != null}) such as after a
|
||||||
|
* configuration change like a screen rotation.</p>
|
||||||
|
*
|
||||||
|
* @param previousBundle Previous bundle that the Activity saved.
|
||||||
|
* @param previousBlurb Previous blurb that the Activity saved
|
||||||
|
*/
|
||||||
|
protected abstract void onPostCreateWithPreviousResult(
|
||||||
|
final Bundle previousBundle, final String previousBlurb);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Bundle for the plug-in or {@code null} if a valid Bundle cannot
|
||||||
|
* be generated.
|
||||||
|
*/
|
||||||
|
protected abstract Bundle getResultBundle();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param bundle Valid bundle for the component.
|
||||||
|
* @return Blurb for {@code bundle}.
|
||||||
|
*/
|
||||||
|
protected abstract String getResultBlurb(final Bundle bundle);
|
||||||
|
}
|
@ -0,0 +1,189 @@
|
|||||||
|
package org.tasks.locale.ui.activity;
|
||||||
|
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.support.design.widget.TextInputEditText;
|
||||||
|
import android.support.v4.content.ContextCompat;
|
||||||
|
import android.support.v7.widget.Toolbar;
|
||||||
|
import android.view.MenuItem;
|
||||||
|
|
||||||
|
import net.dinglisch.android.tasker.TaskerPlugin;
|
||||||
|
|
||||||
|
import org.tasks.R;
|
||||||
|
import org.tasks.billing.PurchaseHelper;
|
||||||
|
import org.tasks.billing.PurchaseHelperCallback;
|
||||||
|
import org.tasks.injection.ActivityComponent;
|
||||||
|
import org.tasks.locale.bundle.TaskCreationBundle;
|
||||||
|
import org.tasks.preferences.Preferences;
|
||||||
|
import org.tasks.ui.MenuColorizer;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import butterknife.BindView;
|
||||||
|
import butterknife.ButterKnife;
|
||||||
|
|
||||||
|
public final class TaskerCreateTaskActivity extends AbstractFragmentPluginAppCompatActivity implements PurchaseHelperCallback, Toolbar.OnMenuItemClickListener {
|
||||||
|
|
||||||
|
private static final int REQUEST_PURCHASE = 10125;
|
||||||
|
private static final String EXTRA_PURCHASE_INITIATED = "extra_purchase_initiated";
|
||||||
|
|
||||||
|
@Inject Preferences preferences;
|
||||||
|
@Inject PurchaseHelper purchaseHelper;
|
||||||
|
|
||||||
|
@BindView(R.id.title) TextInputEditText title;
|
||||||
|
@BindView(R.id.toolbar) Toolbar toolbar;
|
||||||
|
@BindView(R.id.due_date) TextInputEditText dueDate;
|
||||||
|
@BindView(R.id.due_time) TextInputEditText dueTime;
|
||||||
|
@BindView(R.id.priority) TextInputEditText priority;
|
||||||
|
@BindView(R.id.description) TextInputEditText description;
|
||||||
|
|
||||||
|
private Bundle previousBundle;
|
||||||
|
private boolean purchaseInitiated;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(final Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
|
setContentView(R.layout.activity_tasker_create);
|
||||||
|
|
||||||
|
ButterKnife.bind(this);
|
||||||
|
|
||||||
|
toolbar.setTitle(R.string.tasker_create_task);
|
||||||
|
final boolean backButtonSavesTask = preferences.backButtonSavesTask();
|
||||||
|
toolbar.setNavigationIcon(ContextCompat.getDrawable(this,
|
||||||
|
backButtonSavesTask ? R.drawable.ic_close_24dp : R.drawable.ic_save_24dp));
|
||||||
|
toolbar.setNavigationOnClickListener(v -> {
|
||||||
|
if (backButtonSavesTask) {
|
||||||
|
discardButtonClick();
|
||||||
|
} else {
|
||||||
|
save();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
toolbar.setOnMenuItemClickListener(this);
|
||||||
|
toolbar.inflateMenu(R.menu.menu_tasker_create_task);
|
||||||
|
MenuColorizer.colorToolbar(this, toolbar);
|
||||||
|
|
||||||
|
if (savedInstanceState != null) {
|
||||||
|
previousBundle = savedInstanceState.getParcelable(TaskCreationBundle.EXTRA_BUNDLE);
|
||||||
|
purchaseInitiated = savedInstanceState.getBoolean(EXTRA_PURCHASE_INITIATED);
|
||||||
|
TaskCreationBundle bundle = new TaskCreationBundle(previousBundle);
|
||||||
|
title.setText(bundle.getTitle());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!preferences.hasPurchase(R.string.p_purchased_tasker) && !purchaseInitiated) {
|
||||||
|
purchaseInitiated = purchaseHelper.purchase(this, getString(R.string.sku_tasker), getString(R.string.p_purchased_tasker), REQUEST_PURCHASE, this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPostCreateWithPreviousResult(final Bundle previousBundle, final String previousBlurb) {
|
||||||
|
this.previousBundle = previousBundle;
|
||||||
|
TaskCreationBundle bundle = new TaskCreationBundle(previousBundle);
|
||||||
|
title.setText(bundle.getTitle());
|
||||||
|
dueDate.setText(bundle.getDueDate());
|
||||||
|
dueTime.setText(bundle.getDueTime());
|
||||||
|
priority.setText(bundle.getPriority());
|
||||||
|
description.setText(bundle.getDescription());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isBundleValid(final Bundle bundle) {
|
||||||
|
return TaskCreationBundle.isBundleValid(bundle);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Bundle getResultBundle() {
|
||||||
|
TaskCreationBundle bundle = new TaskCreationBundle();
|
||||||
|
bundle.setTitle(title.getText().toString().trim());
|
||||||
|
bundle.setDueDate(dueDate.getText().toString().trim());
|
||||||
|
bundle.setDueTime(dueTime.getText().toString().trim());
|
||||||
|
bundle.setPriority(priority.getText().toString().trim());
|
||||||
|
bundle.setDescription(description.getText().toString().trim());
|
||||||
|
Bundle resultBundle = bundle.build();
|
||||||
|
if (TaskerPlugin.Setting.hostSupportsOnFireVariableReplacement(this)) {
|
||||||
|
TaskerPlugin.Setting.setVariableReplaceKeys(resultBundle, new String[] {
|
||||||
|
TaskCreationBundle.EXTRA_TITLE,
|
||||||
|
TaskCreationBundle.EXTRA_DUE_DATE,
|
||||||
|
TaskCreationBundle.EXTRA_DUE_TIME,
|
||||||
|
TaskCreationBundle.EXTRA_PRIORITY,
|
||||||
|
TaskCreationBundle.EXTRA_DESCRIPTION
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return resultBundle;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getResultBlurb(final Bundle bundle) {
|
||||||
|
return title.getText().toString().trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||||
|
if (requestCode == REQUEST_PURCHASE) {
|
||||||
|
purchaseHelper.handleActivityResult(this, requestCode, resultCode, data);
|
||||||
|
} else {
|
||||||
|
super.onActivityResult(requestCode, resultCode, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBackPressed() {
|
||||||
|
final boolean backButtonSavesTask = preferences.backButtonSavesTask();
|
||||||
|
if (backButtonSavesTask) {
|
||||||
|
save();
|
||||||
|
} else {
|
||||||
|
discardButtonClick();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void save() {
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void discardButtonClick() {
|
||||||
|
mIsCancelled = true;
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDestroy() {
|
||||||
|
super.onDestroy();
|
||||||
|
|
||||||
|
if (!isChangingConfigurations()) {
|
||||||
|
purchaseHelper.disposeIabHelper();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onSaveInstanceState(Bundle outState) {
|
||||||
|
super.onSaveInstanceState(outState);
|
||||||
|
outState.putParcelable(TaskCreationBundle.EXTRA_BUNDLE, previousBundle);
|
||||||
|
outState.putBoolean(EXTRA_PURCHASE_INITIATED, purchaseInitiated);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void inject(ActivityComponent component) {
|
||||||
|
component.inject(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void purchaseCompleted(boolean success, String sku) {
|
||||||
|
if (!success) {
|
||||||
|
discardButtonClick();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onMenuItemClick(MenuItem item) {
|
||||||
|
switch (item.getItemId()) {
|
||||||
|
case R.id.menu_save:
|
||||||
|
save();
|
||||||
|
return true;
|
||||||
|
case R.id.menu_help:
|
||||||
|
startActivity(new Intent(Intent.ACTION_VIEW).setData(Uri.parse("http://tasks.org/help")));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return super.onOptionsItemSelected(item);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,112 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout 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:background="?attr/asContentBackground"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<include layout="@layout/toolbar" />
|
||||||
|
|
||||||
|
<ScrollView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<android.support.constraint.ConstraintLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<android.support.design.widget.TextInputLayout
|
||||||
|
android:id="@+id/textInputLayout"
|
||||||
|
android:layout_width="368dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
|
<android.support.design.widget.TextInputEditText
|
||||||
|
android:id="@+id/title"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="@string/TEA_title_hint"
|
||||||
|
android:inputType="textCapSentences|textAutoCorrect" />
|
||||||
|
</android.support.design.widget.TextInputLayout>
|
||||||
|
|
||||||
|
<android.support.design.widget.TextInputLayout
|
||||||
|
android:id="@+id/textInputLayout2"
|
||||||
|
android:layout_width="368dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/textInputLayout">
|
||||||
|
|
||||||
|
<android.support.design.widget.TextInputEditText
|
||||||
|
android:id="@+id/due_date"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="@string/due_date" />
|
||||||
|
</android.support.design.widget.TextInputLayout>
|
||||||
|
|
||||||
|
<android.support.design.widget.TextInputLayout
|
||||||
|
android:id="@+id/textInputLayout3"
|
||||||
|
android:layout_width="368dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/textInputLayout2">
|
||||||
|
|
||||||
|
<android.support.design.widget.TextInputEditText
|
||||||
|
android:id="@+id/due_time"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="@string/due_time" />
|
||||||
|
</android.support.design.widget.TextInputLayout>
|
||||||
|
|
||||||
|
<android.support.design.widget.TextInputLayout
|
||||||
|
android:id="@+id/textInputLayout4"
|
||||||
|
android:layout_width="368dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/textInputLayout3">
|
||||||
|
|
||||||
|
<android.support.design.widget.TextInputEditText
|
||||||
|
android:id="@+id/priority"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="@string/TEA_importance_label" />
|
||||||
|
</android.support.design.widget.TextInputLayout>
|
||||||
|
|
||||||
|
<android.support.design.widget.TextInputLayout
|
||||||
|
android:layout_width="368dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/textInputLayout4">
|
||||||
|
|
||||||
|
<android.support.design.widget.TextInputEditText
|
||||||
|
android:id="@+id/description"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="@string/TEA_note_label" />
|
||||||
|
</android.support.design.widget.TextInputLayout>
|
||||||
|
|
||||||
|
</android.support.constraint.ConstraintLayout>
|
||||||
|
</ScrollView>
|
||||||
|
|
||||||
|
</LinearLayout>
|
@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
|
||||||
|
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tasks="http://schemas.android.com/apk/res-auto">
|
||||||
|
<item
|
||||||
|
android:id="@+id/menu_help"
|
||||||
|
android:icon="@drawable/ic_help_24dp"
|
||||||
|
android:title="@string/help"
|
||||||
|
tasks:showAsAction="ifRoom"/>
|
||||||
|
</menu>
|
Loading…
Reference in New Issue