Remove section recycler view adapter library

pull/996/head
Alex Baker 4 years ago
parent bbd9a24bc7
commit a0b8338cec

@ -158,7 +158,6 @@ dependencies {
debugImplementation("com.squareup.leakcanary:leakcanary-android:${Versions.leakcanary}")
implementation("org.jetbrains.kotlin:kotlin-stdlib:${Versions.kotlin}")
implementation("io.github.luizgrp.sectionedrecyclerviewadapter:sectionedrecyclerviewadapter:2.0.0")
implementation("com.squareup.okhttp3:okhttp:${Versions.okhttp}")
implementation("com.google.code.gson:gson:2.8.6")
implementation("com.google.android.material:material:1.1.0")

@ -495,11 +495,6 @@
license: The Apache Software License, Version 2.0
licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt
url: http://tools.android.com
- artifact: io.github.luizgrp.sectionedrecyclerviewadapter:sectionedrecyclerviewadapter:+
name: sectionedrecyclerviewadapter
copyrightHolder: Gustavo Pagani
license: MIT License
licenseUrl: http://www.opensource.org/licenses/mit-license.php
- artifact: org.jetbrains.kotlin:kotlin-stdlib:+
name: org.jetbrains.kotlin:kotlin-stdlib
copyrightHolder: JetBrains s.r.o.

@ -482,7 +482,7 @@
android:taskAffinity=""
android:theme="@style/TranslucentDialog"/>
<activity android:name=".preferences.AttributionActivity"/>
<activity android:name=".activities.attribution.AttributionActivity"/>
<activity android:name=".tags.TagPickerActivity" />

@ -1151,19 +1151,6 @@
"url": "http://tools.android.com",
"libraryName": "Android ConstraintLayout Solver"
},
{
"artifactId": {
"name": "sectionedrecyclerviewadapter",
"group": "io.github.luizgrp.sectionedrecyclerviewadapter",
"version": "+"
},
"copyrightHolder": "Gustavo Pagani",
"copyrightStatement": "Copyright &copy; Gustavo Pagani. All rights reserved.",
"license": "MIT License",
"licenseUrl": "http://www.opensource.org/licenses/mit-license.php",
"normalizedLicense": "mit",
"libraryName": "sectionedrecyclerviewadapter"
},
{
"artifactId": {
"name": "kotlin-stdlib",

@ -0,0 +1,87 @@
package org.tasks.activities.attribution;
import static com.google.common.collect.Iterables.transform;
import static com.google.common.collect.Lists.newArrayList;
import android.os.Bundle;
import androidx.appcompat.widget.Toolbar;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import butterknife.BindView;
import butterknife.ButterKnife;
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableListMultimap;
import com.google.common.collect.Multimaps;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.tasks.R;
import org.tasks.activities.attribution.AttributionViewModel.LibraryAttribution;
import org.tasks.injection.ActivityComponent;
import org.tasks.injection.ThemedInjectingAppCompatActivity;
import timber.log.Timber;
public class AttributionActivity extends ThemedInjectingAppCompatActivity {
@BindView(R.id.toolbar)
Toolbar toolbar;
@BindView(R.id.list)
RecyclerView recyclerView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_attributions);
ButterKnife.bind(this);
toolbar.setTitle(R.string.third_party_licenses);
toolbar.setNavigationIcon(R.drawable.ic_outline_arrow_back_24px);
toolbar.setNavigationOnClickListener(v -> finish());
themeColor.apply(toolbar);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
}
@Override
protected void onResume() {
super.onResume();
new ViewModelProvider(this)
.get(AttributionViewModel.class)
.observe(this, this::updateAttributions);
}
private void updateAttributions(List<LibraryAttribution> libraryAttributions) {
List<AttributionRow> rows = new ArrayList<>();
ImmutableListMultimap<String, LibraryAttribution> index =
Multimaps.index(libraryAttributions, LibraryAttribution::getLicense);
ArrayList<String> licenses = new ArrayList<>(index.keySet());
Collections.sort(licenses);
for (String license : licenses) {
rows.add(new AttributionRow(license));
ImmutableList<LibraryAttribution> libraries = index.get(license);
ImmutableListMultimap<String, LibraryAttribution> idx =
Multimaps.index(libraries, LibraryAttribution::getCopyrightHolder);
List<String> copyrightHolders = newArrayList(idx.keySet());
Collections.sort(copyrightHolders);
for (String copyrightHolder : copyrightHolders) {
List<String> libs = newArrayList(transform(idx.get(copyrightHolder),
a -> "\u2022 " + a.getLibraryName()));
Collections.sort(libs);
rows.add(new AttributionRow(copyrightHolder, Joiner.on("\n").join(libs)));
}
}
recyclerView.setAdapter(new AttributionAdapter(rows));
Timber.d(libraryAttributions.toString());
}
@Override
public void inject(ActivityComponent component) {
component.inject(this);
}
}

@ -0,0 +1,47 @@
package org.tasks.activities.attribution;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.RecyclerView.ViewHolder;
import java.util.List;
import org.tasks.R;
public class AttributionAdapter extends RecyclerView.Adapter<ViewHolder> {
private final List<AttributionRow> rows;
AttributionAdapter(List<AttributionRow> rows) {
this.rows = rows;
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
return viewType == 0
? new LicenseHeader(inflater.inflate(R.layout.row_attribution_header, parent, false))
: new LicenseRow(inflater.inflate(R.layout.row_attribution, parent, false));
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
AttributionRow row = rows.get(position);
if (getItemViewType(position) == 0) {
((LicenseHeader) holder).bind(row.getLicense());
} else {
((LicenseRow) holder).bind(row.getCopyrightHolder(), row.getLibraries());
}
}
@Override
public int getItemViewType(int position) {
return rows.get(position).isHeader() ? 0 : 1;
}
@Override
public int getItemCount() {
return rows.size();
}
}

@ -0,0 +1,39 @@
package org.tasks.activities.attribution;
public class AttributionRow {
private final boolean isHeader;
private final String license;
private final String copyrightHolder;
private final String libraries;
AttributionRow(String license) {
this.license = license;
isHeader = true;
copyrightHolder = null;
libraries = null;
}
AttributionRow(String copyrightHolder, String libraries) {
this.copyrightHolder = copyrightHolder;
this.libraries = libraries;
isHeader = false;
license = null;
}
boolean isHeader() {
return isHeader;
}
public String getLicense() {
return license;
}
String getCopyrightHolder() {
return copyrightHolder;
}
public String getLibraries() {
return libraries;
}
}

@ -0,0 +1,77 @@
package org.tasks.activities.attribution;
import android.content.Context;
import androidx.annotation.Keep;
import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.Observer;
import com.google.gson.GsonBuilder;
import io.reactivex.Single;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.schedulers.Schedulers;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.List;
import timber.log.Timber;
@SuppressWarnings({"WeakerAccess", "RedundantSuppression"})
public class AttributionViewModel extends androidx.lifecycle.ViewModel {
private final MutableLiveData<List<LibraryAttribution>> attributions = new MutableLiveData<>();
private final CompositeDisposable disposables = new CompositeDisposable();
private boolean loaded;
void observe(AppCompatActivity activity, Observer<List<LibraryAttribution>> observer) {
attributions.observe(activity, observer);
load(activity);
}
private void load(Context context) {
if (loaded) {
return;
}
loaded = true;
disposables.add(
Single.fromCallable(
() -> {
InputStream licenses = context.getAssets().open("licenses.json");
InputStreamReader reader =
new InputStreamReader(licenses, StandardCharsets.UTF_8);
AttributionList list =
new GsonBuilder().create().fromJson(reader, AttributionList.class);
return list.libraries;
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(attributions::setValue, Timber::e));
}
@Override
protected void onCleared() {
disposables.dispose();
}
static class AttributionList {
List<LibraryAttribution> libraries;
}
static class LibraryAttribution {
String copyrightHolder;
String license;
String libraryName;
String getCopyrightHolder() {
return copyrightHolder;
}
@Keep
String getLicense() {
return license;
}
String getLibraryName() {
return libraryName;
}
}
}

@ -0,0 +1,23 @@
package org.tasks.activities.attribution;
import android.view.View;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import butterknife.BindView;
import butterknife.ButterKnife;
import org.tasks.R;
class LicenseHeader extends RecyclerView.ViewHolder {
@BindView(R.id.license_name)
TextView licenseName;
LicenseHeader(@NonNull View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
void bind(String license) {
licenseName.setText(license);
}
}

@ -0,0 +1,28 @@
package org.tasks.activities.attribution;
import android.view.View;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import butterknife.BindView;
import butterknife.ButterKnife;
import org.tasks.R;
class LicenseRow extends RecyclerView.ViewHolder {
@BindView(R.id.copyright_holder)
TextView copyrightHolder;
@BindView(R.id.libraries)
TextView libraries;
LicenseRow(@NonNull View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
void bind(String copyrightHolder, String libraries) {
this.copyrightHolder.setText(copyrightHolder);
this.libraries.setText(libraries);
}
}

@ -25,7 +25,7 @@ import org.tasks.etesync.EteSyncCalendarSettingsActivity;
import org.tasks.locale.ui.activity.TaskerCreateTaskActivity;
import org.tasks.locale.ui.activity.TaskerSettingsActivity;
import org.tasks.location.LocationPickerActivity;
import org.tasks.preferences.AttributionActivity;
import org.tasks.activities.attribution.AttributionActivity;
import org.tasks.preferences.HelpAndFeedback;
import org.tasks.preferences.MainPreferences;
import org.tasks.preferences.ManageSpaceActivity;

@ -1,142 +0,0 @@
package org.tasks.preferences;
import android.content.Context;
import android.os.Bundle;
import androidx.annotation.Keep;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import butterknife.BindView;
import butterknife.ButterKnife;
import com.google.common.collect.ImmutableListMultimap;
import com.google.common.collect.Multimaps;
import com.google.gson.GsonBuilder;
import io.github.luizgrp.sectionedrecyclerviewadapter.SectionedRecyclerViewAdapter;
import io.reactivex.Single;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.schedulers.Schedulers;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.tasks.R;
import org.tasks.injection.ActivityComponent;
import org.tasks.injection.ThemedInjectingAppCompatActivity;
import timber.log.Timber;
public class AttributionActivity extends ThemedInjectingAppCompatActivity {
@BindView(R.id.toolbar)
Toolbar toolbar;
@BindView(R.id.list)
RecyclerView recyclerView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_attributions);
ButterKnife.bind(this);
toolbar.setTitle(R.string.third_party_licenses);
toolbar.setNavigationIcon(R.drawable.ic_outline_arrow_back_24px);
toolbar.setNavigationOnClickListener(v -> finish());
themeColor.apply(toolbar);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
}
@Override
protected void onResume() {
super.onResume();
new ViewModelProvider(this).get(ViewModel.class).observe(this, this::updateAttributions);
}
private void updateAttributions(List<LibraryAttribution> libraryAttributions) {
SectionedRecyclerViewAdapter adapter = new SectionedRecyclerViewAdapter();
ImmutableListMultimap<String, LibraryAttribution> index =
Multimaps.index(libraryAttributions, LibraryAttribution::getLicense);
ArrayList<String> licenses = new ArrayList<>(index.keySet());
Collections.sort(licenses);
for (String license : licenses) {
adapter.addSection(new AttributionSection(license, index.get(license)));
}
recyclerView.setAdapter(adapter);
Timber.d(libraryAttributions.toString());
}
@Override
public void inject(ActivityComponent component) {
component.inject(this);
}
static class AttributionList {
List<LibraryAttribution> libraries;
}
static class LibraryAttribution {
String copyrightHolder;
String license;
String libraryName;
String getCopyrightHolder() {
return copyrightHolder;
}
@Keep
String getLicense() {
return license;
}
String getLibraryName() {
return libraryName;
}
}
@SuppressWarnings({"WeakerAccess", "RedundantSuppression"})
public static class ViewModel extends androidx.lifecycle.ViewModel {
private final MutableLiveData<List<LibraryAttribution>> attributions = new MutableLiveData<>();
private final CompositeDisposable disposables = new CompositeDisposable();
private boolean loaded;
void observe(AppCompatActivity activity, Observer<List<LibraryAttribution>> observer) {
attributions.observe(activity, observer);
load(activity);
}
private void load(Context context) {
if (loaded) {
return;
}
loaded = true;
disposables.add(
Single.fromCallable(
() -> {
InputStream licenses = context.getAssets().open("licenses.json");
InputStreamReader reader =
new InputStreamReader(licenses, StandardCharsets.UTF_8);
AttributionList list =
new GsonBuilder().create().fromJson(reader, AttributionList.class);
return list.libraries;
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(attributions::setValue, Timber::e));
}
@Override
protected void onCleared() {
disposables.dispose();
}
}
}

@ -1,110 +0,0 @@
package org.tasks.preferences;
import static com.google.common.collect.Iterables.transform;
import static com.google.common.collect.Lists.newArrayList;
import static com.google.common.collect.Maps.newLinkedHashMap;
import android.view.View;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.RecyclerView.ViewHolder;
import butterknife.BindView;
import butterknife.ButterKnife;
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableListMultimap;
import com.google.common.collect.Multimaps;
import io.github.luizgrp.sectionedrecyclerviewadapter.SectionParameters;
import io.github.luizgrp.sectionedrecyclerviewadapter.StatelessSection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.tasks.R;
import org.tasks.preferences.AttributionActivity.LibraryAttribution;
class AttributionSection extends StatelessSection {
private final String license;
private final List<Entry<String, String>> attributions;
AttributionSection(String license, List<LibraryAttribution> attributions) {
super(
SectionParameters.builder()
.itemResourceId(R.layout.row_attribution)
.headerResourceId(R.layout.row_attribution_header)
.build());
this.license = license;
ImmutableListMultimap<String, LibraryAttribution> index =
Multimaps.index(attributions, LibraryAttribution::getCopyrightHolder);
List<String> copyrightHolders = newArrayList(index.keySet());
Collections.sort(copyrightHolders);
Map<String, String> map = newLinkedHashMap();
for (String copyrightHolder : copyrightHolders) {
List<String> libraries = newArrayList(transform(index.get(copyrightHolder),
a -> "\u2022 " + a.getLibraryName()));
Collections.sort(libraries);
map.put(copyrightHolder, Joiner.on("\n").join(libraries));
}
this.attributions = newArrayList(map.entrySet());
}
@Override
public int getContentItemsTotal() {
return attributions.size();
}
@Override
public ViewHolder getHeaderViewHolder(View view) {
return new LicenseHeader(view);
}
@Override
public ViewHolder getItemViewHolder(View view) {
return new LicenseRow(view);
}
@Override
public void onBindHeaderViewHolder(ViewHolder holder) {
((LicenseHeader) holder).bind(license);
}
@Override
public void onBindItemViewHolder(ViewHolder holder, int position) {
Entry<String, String> entry = attributions.get(position);
((LicenseRow) holder).bind(entry.getKey(), entry.getValue());
}
static class LicenseHeader extends RecyclerView.ViewHolder {
@BindView(R.id.license_name)
TextView licenseName;
LicenseHeader(@NonNull View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
void bind(String license) {
licenseName.setText(license);
}
}
static class LicenseRow extends RecyclerView.ViewHolder {
@BindView(R.id.copyright_holder)
TextView copyrightHolder;
@BindView(R.id.libraries)
TextView libraries;
LicenseRow(@NonNull View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
void bind(String copyrightHolder, String libraries) {
this.copyrightHolder.setText(copyrightHolder);
this.libraries.setText(libraries);
}
}
}

@ -47,7 +47,7 @@
android:title="@string/third_party_licenses"
app:icon="@drawable/ic_outline_gavel_24px">
<intent
android:targetClass="org.tasks.preferences.AttributionActivity"
android:targetClass="org.tasks.activities.attribution.AttributionActivity"
android:targetPackage="@string/app_package" />
</Preference>

Loading…
Cancel
Save