Skip to content

Commit f653ee7

Browse files
author
Gabor Keszthelyi
committed
Show subtasks on details view. #442
1 parent 62e6af8 commit f653ee7

32 files changed

+1178
-13
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-provider/build.gradle

+2-2
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,8 @@ dependencies {
3939
exclude module: 'jems'
4040
}
4141
androidTestImplementation 'com.android.support:support-annotations:' + SUPPORT_LIBRARY_VERSION
42-
androidTestImplementation 'com.android.support.test:runner:0.5'
43-
androidTestImplementation 'com.android.support.test:rules:0.5'
42+
androidTestImplementation 'com.android.support.test:runner:' + ANDROID_TEST_RUNNER_VERSION
43+
androidTestImplementation 'com.android.support.test:rules:' + ANDROID_TEST_RUNNER_VERSION
4444
testImplementation 'org.robolectric:robolectric:' + ROBOLECTRIC_VERSION
4545
testImplementation 'junit:junit:4.12'
4646
testImplementation 'org.mockito:mockito-core:2.10.0'

opentasks/build.gradle

+10
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 'com.android.support:appcompat-v7:' + SUPPORT_LIBRARY_VERSION
5054
implementation 'com.android.support:design:' + SUPPORT_LIBRARY_VERSION
5155
implementation('org.dmfs:android-xml-magic:0.1.1') {
@@ -66,10 +70,16 @@ dependencies {
6670
implementation 'org.dmfs:jems:' + JEMS_VERSION
6771
implementation 'org.dmfs:rfc5545-datetime:' + RFC5545_DATETIME_VERSION
6872
implementation 'com.github.dmfs.bolts:color-bolts:' + BOLTS_VERSION
73+
implementation 'io.reactivex.rxjava2:rxjava:2.1.5'
74+
implementation 'io.reactivex.rxjava2:rxandroid:2.0.1'
6975

7076
testImplementation 'junit:junit:4.12'
7177
testImplementation 'org.robolectric:robolectric:3.5.1'
7278

79+
implementation('com.github.dmfs.contentpal:contentpal:' + CONTENTPAL_VERSION) {
80+
exclude module: 'jems'
81+
}
82+
7383
androidTestImplementation('com.android.support.test:runner:' + ANDROID_TEST_RUNNER_VERSION) {
7484
exclude group: 'com.android.support', module: 'support-annotations'
7585
}

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/EditTaskFragment.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
import org.dmfs.tasks.model.OnContentChangeListener;
6161
import org.dmfs.tasks.model.Sources;
6262
import org.dmfs.tasks.model.TaskFieldAdapters;
63+
import org.dmfs.tasks.utils.BasicTaskDetailsUi;
6364
import org.dmfs.tasks.utils.ContentValueMapper;
6465
import org.dmfs.tasks.utils.OnModelLoadedListener;
6566
import org.dmfs.tasks.utils.RecentlyUsedLists;
@@ -793,7 +794,7 @@ public void saveAndExit()
793794
activity.finish();
794795
if (isNewTask)
795796
{
796-
activity.startActivity(new Intent("android.intent.action.VIEW", mTaskUri));
797+
new BasicTaskDetailsUi(mTaskUri).show(activity);
797798
}
798799
}
799800
else

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

+2
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import org.dmfs.android.bolts.color.Color;
3232
import org.dmfs.tasks.model.ContentSet;
3333
import org.dmfs.tasks.utils.BaseActivity;
34+
import org.dmfs.tasks.utils.Darkened;
3435

3536

3637
/**
@@ -152,6 +153,7 @@ public void updateColor(Color color)
152153
{
153154
Window window = getWindow();
154155
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
156+
155157
window.setStatusBarColor(darkenColor(color.argb()));
156158
}
157159
}

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

+33-8
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,15 @@
5151
import android.widget.TextView;
5252

5353
import org.dmfs.android.bolts.color.colors.ValueColor;
54+
55+
import org.dmfs.android.contentpal.RowDataSnapshot;
56+
5457
import org.dmfs.android.retentionmagic.SupportFragment;
5558
import org.dmfs.android.retentionmagic.annotations.Parameter;
5659
import org.dmfs.android.retentionmagic.annotations.Retain;
60+
import org.dmfs.tasks.contract.TaskContract;
5761
import org.dmfs.tasks.contract.TaskContract.Tasks;
62+
import org.dmfs.tasks.data.SubtasksSource;
5863
import org.dmfs.tasks.model.ContentSet;
5964
import org.dmfs.tasks.model.Model;
6065
import org.dmfs.tasks.model.OnContentChangeListener;
@@ -63,13 +68,18 @@
6368
import org.dmfs.tasks.notification.TaskNotificationHandler;
6469
import org.dmfs.tasks.share.ShareIntentFactory;
6570
import org.dmfs.tasks.utils.ContentValueMapper;
71+
import org.dmfs.tasks.utils.Darkened;
6672
import org.dmfs.tasks.utils.OnModelLoadedListener;
73+
import org.dmfs.tasks.widget.SubtasksView;
6774
import org.dmfs.tasks.widget.TaskView;
6875

6976
import java.util.Arrays;
7077
import java.util.HashSet;
7178
import java.util.Set;
7279

80+
import io.reactivex.disposables.CompositeDisposable;
81+
import io.reactivex.functions.Consumer;
82+
7383

7484
/**
7585
* 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
@@ -130,6 +140,8 @@ public class ViewTaskFragment extends SupportFragment
130140
*/
131141
private TaskView mDetailView;
132142

143+
private CompositeDisposable mDisposables;
144+
133145
private int mListColor;
134146
private int mOldStatus = -1;
135147
private boolean mPinned = false;
@@ -207,14 +219,6 @@ public static ViewTaskFragment newInstance(Uri uri)
207219
}
208220

209221

210-
/**
211-
* Mandatory empty constructor for the fragment manager to instantiate the fragment (e.g. upon screen orientation changes).
212-
*/
213-
public ViewTaskFragment()
214-
{
215-
}
216-
217-
218222
@Override
219223
public void onCreate(Bundle savedInstanceState)
220224
{
@@ -265,6 +269,7 @@ public void onDestroyView()
265269
mDetailView.setValues(null);
266270
}
267271

272+
mDisposables.dispose();
268273
}
269274

270275

@@ -319,6 +324,8 @@ else if (mTaskUri != null)
319324
loadUri(uri);
320325
}
321326

327+
mDisposables = new CompositeDisposable();
328+
322329
return mRootView;
323330
}
324331

@@ -400,6 +407,7 @@ public void loadUri(Uri uri)
400407
if ((oldUri == null) != (uri == null))
401408
{
402409
/*
410+
403411
* getActivity().invalidateOptionsMenu() doesn't work in Android 2.x so use the compat lib
404412
*/
405413
ActivityCompat.invalidateOptionsMenu(getActivity());
@@ -715,6 +723,23 @@ public void onContentLoaded(ContentSet contentSet)
715723
postUpdateView();
716724
}
717725
}
726+
727+
mDisposables.add(
728+
new SubtasksSource(mAppContext, mTaskUri)
729+
.subscribe(new Consumer<Iterable<RowDataSnapshot<TaskContract.Tasks>>>()
730+
{
731+
@Override
732+
public void accept(Iterable<RowDataSnapshot<TaskContract.Tasks>> subTasks)
733+
{
734+
if (subTasks.iterator().hasNext())
735+
{
736+
new SubtasksView(mContent).update(subTasks);
737+
((TextView) mContent.findViewById(R.id.opentasks_view_item_task_details_subtitles_section_header))
738+
.setTextColor(new Darkened(mListColor).argb());
739+
mContent.requestLayout();
740+
}
741+
}
742+
}));
718743
}
719744

720745

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
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.data;
18+
19+
import android.content.ContentProviderClient;
20+
import android.os.Build;
21+
22+
import org.dmfs.tasks.utils.rxjava.disposable.DelegatingDisposable;
23+
24+
import io.reactivex.disposables.Disposable;
25+
import io.reactivex.disposables.Disposables;
26+
27+
28+
/**
29+
* {@link Disposable} for {@link ContentProviderClient}.
30+
*
31+
* @author Gabor Keszthelyi
32+
*/
33+
public final class ContentProviderClientDisposable extends DelegatingDisposable
34+
{
35+
public ContentProviderClientDisposable(final ContentProviderClient client)
36+
{
37+
super(Disposables.fromRunnable(new Runnable()
38+
{
39+
@Override
40+
public void run()
41+
{
42+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
43+
{
44+
client.close();
45+
}
46+
else
47+
{
48+
client.release();
49+
}
50+
}
51+
}));
52+
}
53+
54+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
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.data;
18+
19+
import android.content.ContentProviderClient;
20+
import android.content.Context;
21+
import android.net.Uri;
22+
23+
import org.dmfs.provider.tasks.AuthorityUtil;
24+
import org.dmfs.tasks.contract.TaskContract;
25+
import org.dmfs.tasks.utils.rxjava.singlesource.DelegatingSingleSource;
26+
27+
import io.reactivex.Single;
28+
import io.reactivex.SingleEmitter;
29+
import io.reactivex.SingleOnSubscribe;
30+
import io.reactivex.SingleSource;
31+
import io.reactivex.annotations.NonNull;
32+
33+
34+
/**
35+
* {@link SingleSource} for accessing a {@link ContentProviderClient} for the given {@link Uri}.
36+
* Takes care of closing the client upon disposal.
37+
*
38+
* @author Gabor Keszthelyi
39+
*/
40+
public class ContentProviderClientSource extends DelegatingSingleSource<ContentProviderClient>
41+
{
42+
43+
public ContentProviderClientSource(final Context context, final Uri uri)
44+
{
45+
super(Single.create(new SingleOnSubscribe<ContentProviderClient>()
46+
{
47+
@Override
48+
public void subscribe(@NonNull SingleEmitter<ContentProviderClient> emitter) throws Exception
49+
{
50+
ContentProviderClient client = context.getContentResolver().acquireContentProviderClient(uri);
51+
emitter.setDisposable(new ContentProviderClientDisposable(client));
52+
emitter.onSuccess(client);
53+
}
54+
}));
55+
}
56+
57+
58+
public ContentProviderClientSource(Context context)
59+
{
60+
this(context, TaskContract.getContentUri(AuthorityUtil.taskAuthority(context)));
61+
}
62+
63+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
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.data;
18+
19+
import android.content.ContentProviderClient;
20+
import android.content.Context;
21+
22+
import org.dmfs.android.contentpal.RowSet;
23+
24+
25+
/**
26+
* Represents a ContentProvider query resulting in ContentPal's {@link RowSet}.
27+
*
28+
* @author Gabor Keszthelyi
29+
*/
30+
public interface CpQuery<T>
31+
{
32+
33+
/**
34+
* Returns the {@link RowSet} that represent the result of this query.
35+
*/
36+
RowSet<T> rowSet(ContentProviderClient client, Context appContext);
37+
38+
}

0 commit comments

Comments
 (0)