Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,16 @@ If your push (message) is not received or display an error, you can feedback [he
Don't forget to attach your logs by sharing logs zip (Main → Menu → Share logs) and your steps.

# Licenses
GPL v3.0
## The license for this project
GPL v3.0
## Licenses for third-party resources
Licenses of libraries are used in Android client is attached into the app, you can go to Main Menu Open Source Licenses to view them.

Some icons and pictures comes from [icons8.com](https://icons8.com/license), which are free to use for Open Source (Established projects should get the icons for free.)

Licenses of libraries are used in the server:

* Vertx - Eclipse Public License 2.0 and Apache License 2.0
* JUnit - EPL 1.0
* Mockito - MIT
* Power Mockito - Apache 2.0
15 changes: 10 additions & 5 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -91,11 +91,6 @@ dependencies {
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
implementation 'com.elvishew:xlog:1.6.1'
implementation project(':common')
implementation 'moe.shizuku.preference:preference:3.0.0'
implementation 'moe.shizuku.preference:preference-dialog-android:3.0.0'
implementation 'moe.shizuku.preference:preference-simplemenu:3.0.0'
implementation 'com.google.android.material:material:1.1.0-alpha02'
def nav_version = "1.0.0-alpha08"
implementation "android.arch.navigation:navigation-fragment:$nav_version"
Expand All @@ -107,4 +102,14 @@ dependencies {
implementation 'com.google.android.gms:play-services-oss-licenses:16.0.1'
// Fabric
implementation 'com.crashlytics.sdk.android:crashlytics:2.9.8'
// Stream support for Java8-
implementation 'com.annimon:stream:1.2.1'
// Preferences
implementation 'moe.shizuku.preference:preference:3.0.0'
implementation 'moe.shizuku.preference:preference-dialog-android:3.0.0'
implementation 'moe.shizuku.preference:preference-simplemenu:3.0.0'
// Logger
implementation 'com.elvishew:xlog:1.6.1'
// Common
implementation project(':common')
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,25 @@
import android.view.View;
import android.view.ViewGroup;

import com.annimon.stream.Collectors;
import com.annimon.stream.Stream;
import com.elvishew.xlog.Logger;
import com.elvishew.xlog.XLog;
import com.google.android.material.snackbar.Snackbar;
import com.xiaomi.mipush.sdk.MiPushClient;

import java.util.List;
import java.util.stream.Collectors;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import androidx.databinding.DataBindingUtil;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.DiffUtil;
import androidx.recyclerview.widget.RecyclerView;
import moe.yuuta.mipushtester.R;
import moe.yuuta.mipushtester.api.APIManager;
import moe.yuuta.mipushtester.databinding.FragmentTopicSubscriptionBinding;
import moe.yuuta.mipushtester.widgets.multi_state.State;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
Expand All @@ -29,6 +33,7 @@ public class TopicSubscriptionFragment extends Fragment {

private TopicListAdapter mAdapter;
private Call<List<Topic>> mGetTopicListCall;
private State mLoadingState;

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
Expand All @@ -47,20 +52,34 @@ public void onCreate(@Nullable Bundle savedInstanceState) {
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
final View view = inflater.inflate(R.layout.fragment_topic_subscription, container, false);
RecyclerView recyclerView = view.findViewById(R.id.recycler_topic);
final FragmentTopicSubscriptionBinding binding =
DataBindingUtil.inflate(inflater, R.layout.fragment_topic_subscription, container, false);
RecyclerView recyclerView = binding.recyclerTopic;
recyclerView.setAdapter(mAdapter);
return view;
mLoadingState = new State();
mLoadingState.onRetryListener = (v -> call());
binding.setState(mLoadingState);
return binding.getRoot();
}

@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
call();
}

private void call () {
if (mGetTopicListCall != null) {
mGetTopicListCall.cancel();
mGetTopicListCall = null;
}
mGetTopicListCall = APIManager.getInstance().getAvailableTopics();
mLoadingState.showProgress();
mGetTopicListCall.enqueue(new Callback<List<Topic>>() {
@Override
public void onResponse(@NonNull Call<List<Topic>> call, @NonNull Response<List<Topic>> response) {
if (call.isCanceled()) return;
mLoadingState.hideProgress();
if (!response.isSuccessful()) {
onFailure(call, new Exception("Unsuccessful code " + response.code()));
return;
Expand All @@ -72,14 +91,25 @@ public void onResponse(@NonNull Call<List<Topic>> call, @NonNull Response<List<T
public void onFailure(@NonNull Call<List<Topic>> call, @NonNull Throwable t) {
logger.e("Cannot retain topics", t);
if (call.isCanceled()) return;
Snackbar.make(getView(), R.string.error_load_topics, Snackbar.LENGTH_INDEFINITE).show();
mLoadingState.hideProgress();
mLoadingState.icon.set(ContextCompat.getDrawable(requireContext(), R.mipmap.illustration_fetal_error));
mLoadingState.text.set(getString(R.string.error_load_topics));
mLoadingState.description.set(getString(R.string.error_description_global));
}
});
}

private void displayTopicsToUI (List<Topic> originalList) {
if (originalList == null || originalList.size() <= 0) {
mLoadingState.icon.set(ContextCompat.getDrawable(requireContext(), R.mipmap.illustration_list_is_empty));
mLoadingState.text.set(getString(R.string.topic_empty_title));
mLoadingState.showRetry.set(false);
mLoadingState.description.set(getString(R.string.topic_empty_description));
return;
}
mLoadingState.hideAll();
List<String> localSubscribedTopics = MiPushClient.getAllTopic(requireContext());
List<Topic> list = originalList.stream()
List<Topic> list = Stream.of(originalList)
.peek(topic -> topic.setSubscribed(localSubscribedTopics.contains(topic.getId())))
.collect(Collectors.toList());
DiffUtil.DiffResult result = DiffUtil.calculateDiff(new DiffUtil.Callback() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package moe.yuuta.mipushtester.widgets.multi_state;

import android.graphics.drawable.Drawable;
import android.view.View;

import androidx.databinding.ObservableBoolean;
import androidx.databinding.ObservableField;

public class State {
public final ObservableBoolean showProgress;
public final ObservableField<Drawable> icon;
public final ObservableField<CharSequence> text;
public final ObservableField<CharSequence> description;
public final ObservableBoolean showTitle;
public final ObservableBoolean showIcon;
public final ObservableBoolean showDescription;
public View.OnClickListener onRetryListener;
public final ObservableBoolean showRetry;
public final ObservableField<CharSequence> contentDescription;

public State() {
showProgress = new ObservableBoolean(false);
icon = new ObservableField<>();
text = new ObservableField<>();
description = new ObservableField<>();
showRetry = new ObservableBoolean(false);
showTitle = new ObservableBoolean(true);
showDescription = new ObservableBoolean(true);
contentDescription = new ObservableField<>();
showIcon = new ObservableBoolean(true);
}

public void showProgress () {
this.showProgress.set(true);
this.showTitle.set(false);
this.showDescription.set(false);
this.showRetry.set(false);
this.showIcon.set(false);
}

public void hideProgress () {
this.showProgress.set(false);
this.showTitle.set(true);
this.showDescription.set(true);
this.showRetry.set(true);
this.showIcon.set(true);
}

public void hideAll () {
this.showProgress.set(false);
this.showTitle.set(false);
this.showDescription.set(false);
this.showRetry.set(false);
this.showIcon.set(false);
}
}
45 changes: 30 additions & 15 deletions app/src/main/res/layout/fragment_topic_subscription.xml
Original file line number Diff line number Diff line change
@@ -1,16 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
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">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_topic"
android:layout_width="0dp"
android:layout_height="0dp"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
<layout xmlns:bind="http://schemas.android.com/tools">
<data>
<variable
name="state"
type="moe.yuuta.mipushtester.widgets.multi_state.State" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
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">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_topic"
android:layout_width="0dp"
android:layout_height="0dp"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
<include layout="@layout/layout_multi_state"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
bind:state="@{state}" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
75 changes: 75 additions & 0 deletions app/src/main/res/layout/layout_multi_state.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
<?xml version="1.0" encoding="utf-8"?>
<layout>
<data>
<variable
name="state"
type="moe.yuuta.mipushtester.widgets.multi_state.State" />
<import type="android.view.View" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">

<ImageView
android:id="@android:id/icon"
android:layout_width="256dp"
android:layout_height="256dp"
android:contentDescription="@{state.contentDescription}"
android:scaleType="centerCrop"
android:src="@{state.icon}"
android:visibility="@{state.showIcon ? View.VISIBLE : View.GONE}"
android:layout_marginTop="32dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:src="@mipmap/illustration_fetal_error" />
<TextView
android:id="@android:id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/TextAppearance.AppCompat.Title"
android:layout_marginTop="16dp"
android:text="@{state.text}"
android:visibility="@{state.showTitle ? View.VISIBLE : View.GONE}"
app:layout_constraintTop_toBottomOf="@android:id/icon"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
tools:text="@string/app_name"/>
<TextView
android:id="@android:id/summary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/TextAppearance.AppCompat.Subhead"
android:layout_marginTop="8dp"
android:visibility="@{state.showDescription ? View.VISIBLE : View.GONE}"
android:text="@{state.description}"
app:layout_constraintTop_toBottomOf="@android:id/title"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
tools:text="@string/app_name"/>
<Button
android:id="@android:id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="@string/retry"
android:visibility="@{state.showRetry ? View.VISIBLE : View.GONE}"
android:onClick="@{state.onRetryListener}"
app:layout_constraintTop_toBottomOf="@android:id/summary"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
style="@style/Widget.AppCompat.Button.Colored"/>
<ProgressBar
android:id="@android:id/progress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="@{state.showProgress ? View.VISIBLE : View.GONE}"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -105,4 +105,8 @@
<string name="topic_action_title">Subscribe topics</string>
<string name="topic_action_description">Subscribe some topics provided by the author, I\'ll send some messages to these topics</string>
<string name="error_load_topics">Cannot retain topics</string>
<string name="error_description_global">Check your internet access and try again later.</string>
<string name="retry">Retry</string>
<string name="topic_empty_title">Currently empty</string>
<string name="topic_empty_description">We\'ll add more topics here, check it back later.</string>
</resources>