Skip to content

Commit

Permalink
Settings for list view, implements #994 (#998)
Browse files Browse the repository at this point in the history
Add a initial settings screen to tweak the list view items.
  • Loading branch information
dmfs authored Feb 27, 2021
1 parent 15da6e6 commit 8f9444b
Show file tree
Hide file tree
Showing 21 changed files with 317 additions and 222 deletions.
1 change: 1 addition & 0 deletions opentasks/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ dependencies {

implementation 'io.reactivex.rxjava2:rxjava:2.2.21'
implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
implementation 'androidx.preference:preference:1.1.1'
}

if (project.hasProperty('PLAY_STORE_SERVICE_ACCOUNT_CREDENTIALS')) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* Copyright 2017 dmfs GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.dmfs.tasks;

import android.os.Bundle;

import androidx.preference.PreferenceFragmentCompat;


/**
* Fragment for the app appearance settings.
*/
public final class AppAppearanceSettingsFragment extends PreferenceFragmentCompat
{
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey)
{
setPreferencesFromResource(R.xml.appearance_preferences, rootKey);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* Copyright 2017 dmfs GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.dmfs.tasks;

import android.os.Bundle;

import androidx.preference.PreferenceFragmentCompat;


/**
* Fragment for the app notifications settings on Android <8.
*/
public final class AppNotificationSettingsFragment extends PreferenceFragmentCompat
{
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey)
{
setPreferencesFromResource(R.xml.notification_preferences, rootKey);
}
}
29 changes: 27 additions & 2 deletions opentasks/src/main/java/org/dmfs/tasks/AppSettingsActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,26 +16,32 @@

package org.dmfs.tasks;

import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.provider.Settings;
import android.view.MenuItem;

import org.dmfs.tasks.utils.BaseActivity;

import androidx.preference.Preference;
import androidx.preference.PreferenceFragmentCompat;


/**
* Activity for the general app settings screen.
*
* @author Gabor Keszthelyi
*/
public final class AppSettingsActivity extends BaseActivity
public final class AppSettingsActivity extends BaseActivity implements PreferenceFragmentCompat.OnPreferenceStartFragmentCallback
{

@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);

getFragmentManager().beginTransaction()
getSupportFragmentManager().beginTransaction()
.replace(android.R.id.content, new AppSettingsFragment())
.commit();

Expand All @@ -54,4 +60,23 @@ public boolean onOptionsItemSelected(MenuItem item)
return super.onOptionsItemSelected(item);
}


@Override
public boolean onPreferenceStartFragment(PreferenceFragmentCompat caller, Preference pref)
{
if (Build.VERSION.SDK_INT >= 26 && "notifications".equalsIgnoreCase(pref.getKey()))
{
// open the system notification settings
Intent intent = new Intent();
intent.setAction(Settings.ACTION_APP_NOTIFICATION_SETTINGS);
intent.putExtra(Settings.EXTRA_APP_PACKAGE, getPackageName());
startActivity(intent);
return true;
}
getSupportFragmentManager().beginTransaction()
.replace(android.R.id.content, getSupportFragmentManager().getFragmentFactory().instantiate(getClassLoader(), pref.getFragment()))
.addToBackStack("")
.commit();
return true;
}
}
15 changes: 5 additions & 10 deletions opentasks/src/main/java/org/dmfs/tasks/AppSettingsFragment.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,23 +17,18 @@
package org.dmfs.tasks;

import android.os.Bundle;
import android.preference.PreferenceFragment;
import androidx.annotation.Nullable;

import androidx.preference.PreferenceFragmentCompat;


/**
* Fragment for the general app settings.
*
* @author Gabor Keszthelyi
*/
public final class AppSettingsFragment extends PreferenceFragment
public final class AppSettingsFragment extends PreferenceFragmentCompat
{

@Override
public void onCreate(@Nullable Bundle savedInstanceState)
public void onCreatePreferences(Bundle savedInstanceState, String rootKey)
{
super.onCreate(savedInstanceState);

addPreferencesFromResource(R.xml.app_preferences);
setPreferencesFromResource(R.xml.app_preferences, rootKey);
}
}
15 changes: 1 addition & 14 deletions opentasks/src/main/java/org/dmfs/tasks/TaskListActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,8 @@
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Build.VERSION;
import android.os.Bundle;
import android.os.Handler;
import android.provider.Settings;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
Expand Down Expand Up @@ -627,18 +625,7 @@ else if (item.getItemId() == R.id.menu_visible_list)
}
else if (item.getItemId() == R.id.opentasks_menu_app_settings)
{
if (VERSION.SDK_INT < 26)
{
startActivity(new Intent(this, AppSettingsActivity.class));
}
else
{
// for now just open the notification settings, which is all we currently support anyway
Intent intent = new Intent();
intent.setAction(Settings.ACTION_APP_NOTIFICATION_SETTINGS);
intent.putExtra(Settings.EXTRA_APP_PACKAGE, getPackageName());
startActivity(intent);
}
startActivity(new Intent(this, AppSettingsActivity.class));
return true;
}
else
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.graphics.drawable.Drawable;
import android.text.Spannable;
Expand Down Expand Up @@ -51,6 +52,7 @@
import androidx.annotation.NonNull;
import androidx.collection.SparseArrayCompat;
import androidx.core.content.ContextCompat;
import androidx.preference.PreferenceManager;

import static android.text.Spanned.SPAN_EXCLUSIVE_EXCLUSIVE;
import static org.dmfs.tasks.contract.TaskContract.TaskColumns.STATUS_CANCELLED;
Expand All @@ -66,8 +68,8 @@
public abstract class BaseTaskViewDescriptor implements ViewDescriptor
{

private final static Pattern CHECKED_PATTERN = Pattern.compile("(-\\s*)?\\[[xX]]");
private final static Pattern UNCHECKED_PATTERN = Pattern.compile("(-\\s*)?\\[\\s?]");
private final static int[] DRAWABLES = new int[] { R.drawable.ic_outline_check_box_24, R.drawable.ic_outline_check_box_outline_blank_24 };
private final static Pattern DRAWABLE_PATTERN = Pattern.compile("((?:-\\s*)?\\[[xX]])|((?:-\\s*)?\\[\\s?])");
/**
* We use this to get the current time.
*/
Expand Down Expand Up @@ -136,25 +138,30 @@ protected void setOverlay(View view, int position, int count)

protected void setDescription(View view, Cursor cursor)
{
Context context = view.getContext();
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
boolean isClosed = TaskAdapter.IS_CLOSED.getFrom(cursor);
TextView descriptionView = getView(view, android.R.id.text1);
int maxDescriptionLines = prefs.getInt(context.getString(R.string.opentasks_pref_appearance_list_description_lines),
context.getResources().getInteger(R.integer.opentasks_preferences_description_lines_default));

List<DescriptionItem> checkList = TaskFieldAdapters.DESCRIPTION_CHECKLIST.get(cursor);
if (checkList.size() > 0 && !checkList.get(0).checkbox && !isClosed)
if (maxDescriptionLines > 0 && checkList.size() > 0 && !checkList.get(0).checkbox && !isClosed)
{
String description = checkList.get(0).text;
descriptionView.setVisibility(View.VISIBLE);
descriptionView.setText(description);
descriptionView.setText(withCheckBoxes(descriptionView, checkList.get(0).text));
descriptionView.setMaxLines(maxDescriptionLines);
}
else
{
descriptionView.setVisibility(View.GONE);
}

String progress = prefs.getString(context.getString(R.string.opentasks_pref_appearance_list_progress), "checked");
TextView checkboxItemCountView = getView(view, R.id.checkbox_item_count);
Iterable<DescriptionItem> checkedItems = new Sieved<>(item -> item.checkbox, checkList);
int checkboxItemCount = new Reduced<DescriptionItem, Integer>(() -> 0, (count, ignored) -> count + 1, checkedItems).value();
if (checkboxItemCount == 0 || isClosed)
if (checkboxItemCount == 0 || isClosed || "none".equals(progress))
{
checkboxItemCountView.setVisibility(View.GONE);
}
Expand All @@ -167,18 +174,18 @@ protected void setDescription(View view, Cursor cursor)
{
checkboxItemCountView.setText(
withCheckBoxes(checkboxItemCountView,
view.getContext().getString(R.string.opentasks_checkbox_item_count_none_checked, checkboxItemCount)));
context.getString(R.string.opentasks_checkbox_item_count_none_checked, checkboxItemCount)));
}
else if (checked == checkboxItemCount)
{
checkboxItemCountView.setText(
withCheckBoxes(checkboxItemCountView,
view.getContext().getString(R.string.opentasks_checkbox_item_count_all_checked, checkboxItemCount)));
context.getString(R.string.opentasks_checkbox_item_count_all_checked, checkboxItemCount)));
}
else
{
checkboxItemCountView.setText(withCheckBoxes(checkboxItemCountView,
view.getContext().getString(R.string.opentasks_checkbox_item_count_partially_checked, checkboxItemCount - checked, checked)));
context.getString(R.string.opentasks_checkbox_item_count_partially_checked, checkboxItemCount - checked, checked)));
}
}
}
Expand All @@ -190,27 +197,24 @@ private Spannable withCheckBoxes(
{
return withDrawable(
view,
withDrawable(
view,
new SpannableString(s),
CHECKED_PATTERN,
R.drawable.ic_outline_check_box_24),
UNCHECKED_PATTERN,
R.drawable.ic_outline_check_box_outline_blank_24);
new SpannableString(s),
DRAWABLE_PATTERN,
DRAWABLES);
}


private Spannable withDrawable(
@NonNull TextView view,
@NonNull Spannable s,
@NonNull Pattern pattern,
@DrawableRes int drawable)
@DrawableRes int[] drawable)
{
Context context = view.getContext();
Matcher matcher = pattern.matcher(s.toString());
while (matcher.find())
{
Drawable drawable1 = ContextCompat.getDrawable(context, drawable);
int idx = matcher.group(1) == null ? 1 : 0;
Drawable drawable1 = ContextCompat.getDrawable(context, drawable[idx]);
int lineHeight = view.getLineHeight();
int additionalSpace = (int) ((lineHeight - view.getTextSize()) / 2);
drawable1.setBounds(0, 0, lineHeight + additionalSpace, lineHeight + additionalSpace);
Expand All @@ -222,6 +226,35 @@ private Spannable withDrawable(
}


protected void setPrio(SharedPreferences prefs, View view, Cursor cursor)
{
// display priority
View prioLabel = getView(view, R.id.priority_label);
int priority = TaskFieldAdapters.PRIORITY.get(cursor);
if (priority > 0 &&
prefs.getBoolean(prioLabel.getContext().getString(R.string.opentasks_pref_appearance_list_show_priority), true))
{
if (priority < 5)
{
prioLabel.setBackgroundColor(new AttributeColor(prioLabel.getContext(), R.attr.colorHighPriority).argb());
}
if (priority == 5)
{
prioLabel.setBackgroundColor(new AttributeColor(prioLabel.getContext(), R.attr.colorMediumPriority).argb());
}
if (priority > 5)
{
prioLabel.setBackgroundColor(new AttributeColor(prioLabel.getContext(), R.attr.colorLowPriority).argb());
}
prioLabel.setVisibility(View.VISIBLE);
}
else
{
prioLabel.setVisibility(View.GONE);
}
}


protected void setColorBar(View view, Cursor cursor)
{
MaterialCardView cardView = getView(view, R.id.flingContentView);
Expand Down
Loading

0 comments on commit 8f9444b

Please sign in to comment.