Skip to content

Commit 15250db

Browse files
Gabor Keszthelyidmfs
Gabor Keszthelyi
authored andcommitted
Show subtasks on details view. #442
1 parent 7c93b86 commit 15250db

36 files changed

+1339
-82
lines changed

.idea/dictionaries/dictionary.xml

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

opentasks/build.gradle

+7
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,14 @@ android {
4242
sourceCompatibility JavaVersion.VERSION_1_8
4343
targetCompatibility JavaVersion.VERSION_1_8
4444
}
45+
dataBinding {
46+
enabled = true
47+
}
4548
}
4649

4750
dependencies {
4851
implementation project(':opentasks-provider')
52+
implementation project(':opentaskspal')
4953
implementation deps.support_appcompat
5054
implementation deps.support_design
5155
implementation(deps.xml_magic) {
@@ -66,6 +70,9 @@ dependencies {
6670
implementation deps.jems
6771
implementation deps.datetime
6872
implementation deps.bolts_color
73+
implementation deps.contentpal
74+
implementation 'io.reactivex.rxjava2:rxjava:2.1.5'
75+
implementation 'io.reactivex.rxjava2:rxandroid:2.0.1'
6976

7077
testImplementation deps.junit
7178
testImplementation deps.robolectric

opentasks/proguard.cfg

+4-1
Original file line numberDiff line numberDiff line change
@@ -77,4 +77,7 @@
7777
java.lang.String TAG;
7878
@org.dmfs.android.retentionmagic.annotations.* <fields>;
7979
private long mId;
80-
}
80+
}
81+
82+
-dontwarn android.databinding.**
83+
-keep class android.databinding.** { *; }

opentasks/src/main/java/org/dmfs/tasks/ViewTaskFragment.java

+16
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,10 @@
5757
import org.dmfs.android.retentionmagic.annotations.Parameter;
5858
import org.dmfs.android.retentionmagic.annotations.Retain;
5959
import org.dmfs.tasks.contract.TaskContract.Tasks;
60+
import org.dmfs.tasks.detailsscreen.RowDataSubtaskViewParams;
61+
import org.dmfs.tasks.detailsscreen.RowDataSubtasksViewParams;
62+
import org.dmfs.tasks.detailsscreen.SubtasksSource;
63+
import org.dmfs.tasks.detailsscreen.SubtasksView;
6064
import org.dmfs.tasks.model.ContentSet;
6165
import org.dmfs.tasks.model.Model;
6266
import org.dmfs.tasks.model.OnContentChangeListener;
@@ -73,6 +77,8 @@
7377
import java.util.HashSet;
7478
import java.util.Set;
7579

80+
import io.reactivex.disposables.CompositeDisposable;
81+
7682

7783
/**
7884
* A fragment representing a single Task detail screen. This fragment is either contained in a {@link TaskListActivity} in two-pane mode (on tablets) or in a
@@ -134,6 +140,8 @@ public class ViewTaskFragment extends SupportFragment
134140
*/
135141
private TaskView mDetailView;
136142

143+
private CompositeDisposable mDisposables;
144+
137145
private int mListColor;
138146
private int mOldStatus = -1;
139147
private boolean mPinned = false;
@@ -251,12 +259,14 @@ public void onDestroyView()
251259
mDetailView.setValues(null);
252260
}
253261

262+
mDisposables.dispose();
254263
}
255264

256265

257266
@Override
258267
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
259268
{
269+
mDisposables = new CompositeDisposable();
260270
mShowFloatingActionButton = !getResources().getBoolean(R.bool.has_two_panes);
261271

262272
mRootView = inflater.inflate(R.layout.fragment_task_view_detail, container, false);
@@ -439,6 +449,12 @@ private void updateView()
439449
((TextView) mToolBar.findViewById(R.id.toolbar_title)).setText(TaskFieldAdapters.TITLE.get(mContentSet));
440450
}
441451
}
452+
453+
mDisposables.add(new SubtasksSource(mAppContext, mTaskUri, RowDataSubtaskViewParams.SUBTASK_PROJECTION)
454+
.subscribe(subtasks ->
455+
{
456+
new SubtasksView(mContent).update(new RowDataSubtasksViewParams(new ValueColor(mListColor), subtasks));
457+
}));
442458
}
443459

444460

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
/*
2+
* Copyright 2018 dmfs GmbH
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.dmfs.tasks.detailsscreen;
18+
19+
import org.dmfs.android.bolts.color.Color;
20+
import org.dmfs.android.contentpal.Projection;
21+
import org.dmfs.android.contentpal.RowDataSnapshot;
22+
import org.dmfs.android.contentpal.projections.Composite;
23+
import org.dmfs.opentaskspal.readdata.EffectiveDueDate;
24+
import org.dmfs.opentaskspal.readdata.EffectiveTaskColor;
25+
import org.dmfs.opentaskspal.readdata.Id;
26+
import org.dmfs.opentaskspal.readdata.PercentComplete;
27+
import org.dmfs.opentaskspal.readdata.TaskTitle;
28+
import org.dmfs.optional.Optional;
29+
import org.dmfs.rfc5545.DateTime;
30+
import org.dmfs.tasks.contract.TaskContract;
31+
32+
33+
/**
34+
* {@link SubtasksView.Params} that reads the data from the given {@link RowDataSnapshot}.
35+
*
36+
* @author Gabor Keszthelyi
37+
*/
38+
public final class RowDataSubtaskViewParams implements SubtaskView.Params
39+
{
40+
41+
/**
42+
* The projection required for this adapter to work.
43+
*/
44+
public static final Projection<TaskContract.Tasks> SUBTASK_PROJECTION = new Composite<>(
45+
Id.projection(),
46+
TaskTitle.PROJECTION,
47+
EffectiveDueDate.PROJECTION,
48+
EffectiveTaskColor.PROJECTION,
49+
PercentComplete.PROJECTION
50+
);
51+
52+
private final RowDataSnapshot<TaskContract.Tasks> mRowDataSnapshot;
53+
54+
55+
public RowDataSubtaskViewParams(RowDataSnapshot<TaskContract.Tasks> rowDataSnapshot)
56+
{
57+
mRowDataSnapshot = rowDataSnapshot;
58+
}
59+
60+
61+
@Override
62+
public Long id()
63+
{
64+
return new Id(mRowDataSnapshot).value();
65+
}
66+
67+
68+
@Override
69+
public Optional<CharSequence> title()
70+
{
71+
return new TaskTitle(mRowDataSnapshot);
72+
}
73+
74+
75+
@Override
76+
public Optional<DateTime> due()
77+
{
78+
return new EffectiveDueDate(mRowDataSnapshot);
79+
}
80+
81+
82+
@Override
83+
public Color color()
84+
{
85+
return new EffectiveTaskColor(mRowDataSnapshot);
86+
}
87+
88+
89+
@Override
90+
public Optional<Integer> percentComplete()
91+
{
92+
return new PercentComplete(mRowDataSnapshot);
93+
}
94+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
* Copyright 2018 dmfs GmbH
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.dmfs.tasks.detailsscreen;
18+
19+
import org.dmfs.android.bolts.color.Color;
20+
import org.dmfs.android.contentpal.RowDataSnapshot;
21+
import org.dmfs.jems.iterable.decorators.Mapped;
22+
import org.dmfs.tasks.contract.TaskContract;
23+
24+
25+
/**
26+
* {@link SubtasksView.Params} that adapts the given {@link RowDataSnapshot}s (and takes the list color).
27+
*
28+
* @author Gabor Keszthelyi
29+
*/
30+
public final class RowDataSubtasksViewParams implements SubtasksView.Params
31+
{
32+
private final Color mTaskListColor;
33+
private final Iterable<RowDataSnapshot<TaskContract.Tasks>> mSubtaskRows;
34+
35+
36+
public RowDataSubtasksViewParams(Color taskListColor, Iterable<RowDataSnapshot<TaskContract.Tasks>> subtaskRows)
37+
{
38+
mTaskListColor = taskListColor;
39+
mSubtaskRows = subtaskRows;
40+
}
41+
42+
43+
@Override
44+
public Color taskListColor()
45+
{
46+
return mTaskListColor;
47+
}
48+
49+
50+
@Override
51+
public Iterable<SubtaskView.Params> subtasks()
52+
{
53+
return new Mapped<>(RowDataSubtaskViewParams::new, mSubtaskRows);
54+
}
55+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
/*
2+
* Copyright 2017 dmfs GmbH
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.dmfs.tasks.detailsscreen;
18+
19+
import android.content.Context;
20+
import android.content.Intent;
21+
import android.databinding.DataBindingUtil;
22+
import android.support.annotation.NonNull;
23+
import android.support.annotation.Nullable;
24+
import android.util.AttributeSet;
25+
import android.view.View;
26+
import android.widget.FrameLayout;
27+
28+
import org.dmfs.android.bolts.color.Color;
29+
import org.dmfs.optional.Optional;
30+
import org.dmfs.rfc5545.DateTime;
31+
import org.dmfs.tasks.R;
32+
import org.dmfs.tasks.databinding.OpentasksViewItemTaskDetailsSubtaskBinding;
33+
import org.dmfs.tasks.readdata.TaskContentUri;
34+
import org.dmfs.tasks.utils.DateFormatter;
35+
import org.dmfs.tasks.utils.DateFormatter.DateFormatContext;
36+
import org.dmfs.tasks.widget.ProgressBackgroundView;
37+
import org.dmfs.tasks.widget.SmartView;
38+
39+
40+
/**
41+
* {@link View} for showing a subtask on the details screen.
42+
*
43+
* @author Gabor Keszthelyi
44+
*/
45+
public final class SubtaskView extends FrameLayout implements SmartView<SubtaskView.Params>
46+
{
47+
48+
public interface Params // i.e. fields of the subtask
49+
{
50+
Long id();
51+
52+
Optional<CharSequence> title();
53+
54+
Optional<DateTime> due();
55+
56+
Color color();
57+
58+
Optional<Integer> percentComplete();
59+
}
60+
61+
62+
public SubtaskView(@NonNull Context context, @Nullable AttributeSet attrs)
63+
{
64+
super(context, attrs);
65+
}
66+
67+
68+
@Override
69+
public void update(Params subtask)
70+
{
71+
OpentasksViewItemTaskDetailsSubtaskBinding views = DataBindingUtil.bind(this);
72+
73+
views.opentasksTaskDetailsSubtaskTitle.setText(subtask.title().value(getContext().getString(R.string.opentasks_task_details_subtask_untitled)));
74+
75+
if (subtask.due().isPresent())
76+
{
77+
views.opentasksTaskDetailsSubtaskDue.setText(
78+
new DateFormatter(getContext()).format(subtask.due().value(), DateTime.now(), DateFormatContext.LIST_VIEW));
79+
}
80+
81+
views.opentasksTaskDetailsSubtaskListRibbon.setBackgroundColor(subtask.color().argb());
82+
83+
new ProgressBackgroundView(views.opentasksTaskDetailsSubtaskProgressBackground)
84+
.update(subtask.percentComplete());
85+
86+
views.getRoot().setOnClickListener((v) ->
87+
{
88+
Context ctx = v.getContext();
89+
// TODO Use BasicTaskDetailsUi class when #589 is merged
90+
ctx.startActivity(new Intent(Intent.ACTION_VIEW, new TaskContentUri(subtask.id(), ctx).value()));
91+
});
92+
}
93+
}

0 commit comments

Comments
 (0)