diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/activities/BaseMainActivity.java b/app/src/main/java/fr/gouv/etalab/mastodon/activities/BaseMainActivity.java index a83250e48..fe8bc57d1 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/activities/BaseMainActivity.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/activities/BaseMainActivity.java @@ -121,6 +121,7 @@ import fr.gouv.etalab.mastodon.fragments.DisplayHowToFragment; import fr.gouv.etalab.mastodon.fragments.DisplayListsFragment; import fr.gouv.etalab.mastodon.fragments.DisplayMutedInstanceFragment; import fr.gouv.etalab.mastodon.fragments.DisplayNotificationsFragment; +import fr.gouv.etalab.mastodon.fragments.DisplayPeertubeNotificationsFragment; import fr.gouv.etalab.mastodon.fragments.DisplayStatusFragment; import fr.gouv.etalab.mastodon.fragments.SettingsPeertubeFragment; import fr.gouv.etalab.mastodon.fragments.TabLayoutScheduleFragment; @@ -2043,6 +2044,13 @@ public abstract class BaseMainActivity extends BaseActivity fragmentManager.beginTransaction() .replace(R.id.main_app_container, settingsPeertubeFragment, fragmentTag).commit(); + }else if (id == R.id.nav_peertube_notifications) { + toot.hide(); + DisplayPeertubeNotificationsFragment displayPeertubeNotificationsFragment= new DisplayPeertubeNotificationsFragment(); + fragmentTag = "PEERTUBE_NOTIFICATIONS"; + fragmentManager.beginTransaction() + .replace(R.id.main_app_container, displayPeertubeNotificationsFragment, fragmentTag).commit(); + }else if (id == R.id.nav_favorites || id == R.id.nav_pixelfed_favorites) { toot.hide(); statusFragment = new DisplayStatusFragment(); diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/client/Entities/PeertubeAccountNotification.java b/app/src/main/java/fr/gouv/etalab/mastodon/client/Entities/PeertubeAccountNotification.java new file mode 100644 index 000000000..05723155e --- /dev/null +++ b/app/src/main/java/fr/gouv/etalab/mastodon/client/Entities/PeertubeAccountNotification.java @@ -0,0 +1,70 @@ +/* Copyright 2017 Thomas Schneider + * + * This file is a part of Mastalab + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 3 of the + * License, or (at your option) any later version. + * + * Mastalab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along with Mastalab; if not, + * see . */ +package fr.gouv.etalab.mastodon.client.Entities; + + + +/** + * Created by Thomas on 23/01/2019. + */ + +public class PeertubeAccountNotification { + + private String id; + private String avatar; + private String displayName; + private String name; + private String type; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getAvatar() { + return avatar; + } + + public void setAvatar(String avatar) { + this.avatar = avatar; + } + + public String getDisplayName() { + return displayName; + } + + public void setDisplayName(String displayName) { + this.displayName = displayName; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } +} diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/client/Entities/PeertubeActorFollow.java b/app/src/main/java/fr/gouv/etalab/mastodon/client/Entities/PeertubeActorFollow.java new file mode 100644 index 000000000..b663a7d67 --- /dev/null +++ b/app/src/main/java/fr/gouv/etalab/mastodon/client/Entities/PeertubeActorFollow.java @@ -0,0 +1,54 @@ +/* Copyright 2018 Thomas Schneider + * + * This file is a part of Mastalab + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 3 of the + * License, or (at your option) any later version. + * + * Mastalab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along with Mastalab; if not, + * see . */ +package fr.gouv.etalab.mastodon.client.Entities; + +/** + * Created by Thomas on 23/01/2019. + * Manage Peertube follow + */ +public class PeertubeActorFollow { + + private String id; + private PeertubeAccountNotification follower; + private PeertubeAccountNotification following; + + public PeertubeActorFollow() { + } + + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public PeertubeAccountNotification getFollower() { + return follower; + } + + public void setFollower(PeertubeAccountNotification follower) { + this.follower = follower; + } + + public PeertubeAccountNotification getFollowing() { + return following; + } + + public void setFollowing(PeertubeAccountNotification following) { + this.following = following; + } +} diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/client/Entities/PeertubeComment.java b/app/src/main/java/fr/gouv/etalab/mastodon/client/Entities/PeertubeComment.java new file mode 100644 index 000000000..a35a82cc4 --- /dev/null +++ b/app/src/main/java/fr/gouv/etalab/mastodon/client/Entities/PeertubeComment.java @@ -0,0 +1,63 @@ +/* Copyright 2018 Thomas Schneider + * + * This file is a part of Mastalab + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 3 of the + * License, or (at your option) any later version. + * + * Mastalab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along with Mastalab; if not, + * see . */ +package fr.gouv.etalab.mastodon.client.Entities; + +/** + * Created by Thomas on 23/01/2019. + * Manage Peertube comments + */ +public class PeertubeComment { + + private String id; + private String threadId; + private PeertubeVideoNotification peertubeVideoNotification; + private PeertubeAccountNotification peertubeAccountNotification; + + public PeertubeComment() { + } + + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getThreadId() { + return threadId; + } + + public void setThreadId(String threadId) { + this.threadId = threadId; + } + + public PeertubeVideoNotification getPeertubeVideoNotification() { + return peertubeVideoNotification; + } + + public void setPeertubeVideoNotification(PeertubeVideoNotification peertubeVideoNotification) { + this.peertubeVideoNotification = peertubeVideoNotification; + } + + public PeertubeAccountNotification getPeertubeAccountNotification() { + return peertubeAccountNotification; + } + + public void setPeertubeAccountNotification(PeertubeAccountNotification peertubeAccountNotification) { + this.peertubeAccountNotification = peertubeAccountNotification; + } +} diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/client/Entities/PeertubeNotification.java b/app/src/main/java/fr/gouv/etalab/mastodon/client/Entities/PeertubeNotification.java new file mode 100644 index 000000000..5593553c9 --- /dev/null +++ b/app/src/main/java/fr/gouv/etalab/mastodon/client/Entities/PeertubeNotification.java @@ -0,0 +1,94 @@ +/* Copyright 2017 Thomas Schneider + * + * This file is a part of Mastalab + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 3 of the + * License, or (at your option) any later version. + * + * Mastalab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along with Mastalab; if not, + * see . */ +package fr.gouv.etalab.mastodon.client.Entities; + + + +import java.util.Date; + +/** + * Created by Thomas on 23/01/2019. + */ + +public class PeertubeNotification { + + private String id; + private boolean read; + private Date updatedAt; + private int type; + private PeertubeComment peertubeComment; + private PeertubeVideoNotification peertubeVideoNotification; + private PeertubeActorFollow peertubeActorFollow; + + public PeertubeNotification(){}; + + public String getId() { + return id; + } + + + public void setId(String id) { + this.id = id; + } + + public boolean isRead() { + return read; + } + + public void setRead(boolean read) { + this.read = read; + } + + public Date getUpdatedAt() { + return updatedAt; + } + + public void setUpdatedAt(Date updatedAt) { + this.updatedAt = updatedAt; + } + + public int getType() { + return type; + } + + public void setType(int type) { + this.type = type; + } + + public PeertubeComment getPeertubeComment() { + return peertubeComment; + } + + public void setPeertubeComment(PeertubeComment peertubeComment) { + this.peertubeComment = peertubeComment; + } + + + public PeertubeActorFollow getPeertubeActorFollow() { + return peertubeActorFollow; + } + + public void setPeertubeActorFollow(PeertubeActorFollow peertubeActorFollow) { + this.peertubeActorFollow = peertubeActorFollow; + } + + public PeertubeVideoNotification getPeertubeVideoNotification() { + return peertubeVideoNotification; + } + + public void setPeertubeVideoNotification(PeertubeVideoNotification peertubeVideoNotification) { + this.peertubeVideoNotification = peertubeVideoNotification; + } +} diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/client/Entities/PeertubeVideoNotification.java b/app/src/main/java/fr/gouv/etalab/mastodon/client/Entities/PeertubeVideoNotification.java new file mode 100644 index 000000000..78329e2e0 --- /dev/null +++ b/app/src/main/java/fr/gouv/etalab/mastodon/client/Entities/PeertubeVideoNotification.java @@ -0,0 +1,61 @@ +/* Copyright 2017 Thomas Schneider + * + * This file is a part of Mastalab + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 3 of the + * License, or (at your option) any later version. + * + * Mastalab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along with Mastalab; if not, + * see . */ +package fr.gouv.etalab.mastodon.client.Entities; + + + +/** + * Created by Thomas on 23/01/2019. + */ + +public class PeertubeVideoNotification { + + private String id; + private PeertubeAccountNotification peertubeAccountNotification; + private String uuid; + private String name; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public PeertubeAccountNotification getPeertubeAccountNotification() { + return peertubeAccountNotification; + } + + public void setPeertubeAccountNotification(PeertubeAccountNotification peertubeAccountNotification) { + this.peertubeAccountNotification = peertubeAccountNotification; + } + + public String getUuid() { + return uuid; + } + + public void setUuid(String uuid) { + this.uuid = uuid; + } +} diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/drawers/PeertubeNotificationsListAdapter.java b/app/src/main/java/fr/gouv/etalab/mastodon/drawers/PeertubeNotificationsListAdapter.java new file mode 100644 index 000000000..acf850b1e --- /dev/null +++ b/app/src/main/java/fr/gouv/etalab/mastodon/drawers/PeertubeNotificationsListAdapter.java @@ -0,0 +1,231 @@ +package fr.gouv.etalab.mastodon.drawers; +/* Copyright 2019 Thomas Schneider + * + * This file is a part of Mastalab + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 3 of the + * License, or (at your option) any later version. + * + * Mastalab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along with Mastalab; if not, + * see . */ + +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.v4.content.ContextCompat; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import java.util.List; + +import fr.gouv.etalab.mastodon.R; +import fr.gouv.etalab.mastodon.activities.PeertubeActivity; +import fr.gouv.etalab.mastodon.activities.ShowAccountActivity; +import fr.gouv.etalab.mastodon.client.Entities.Notification; +import fr.gouv.etalab.mastodon.client.Entities.PeertubeAccountNotification; +import fr.gouv.etalab.mastodon.client.Entities.PeertubeNotification; +import fr.gouv.etalab.mastodon.client.Entities.PeertubeVideoNotification; +import fr.gouv.etalab.mastodon.fragments.DisplayPeertubeNotificationsFragment; +import fr.gouv.etalab.mastodon.helper.Helper; + +import static fr.gouv.etalab.mastodon.helper.Helper.THEME_BLACK; +import static fr.gouv.etalab.mastodon.helper.Helper.THEME_DARK; + + + +/** + * Created by Thomas on 23/01/2019. + * Adapter for Peertube notifications + */ + +public class PeertubeNotificationsListAdapter extends RecyclerView.Adapter { + + private Context context; + private List notifications; + private LayoutInflater layoutInflater; + private PeertubeNotificationsListAdapter peertubeNotificationsListAdapter; + private PeertubeNotificationsListAdapter.ViewHolder holder; + private int style; + + public PeertubeNotificationsListAdapter(Context context, List notifications){ + this.context = context; + this.notifications = notifications; + layoutInflater = LayoutInflater.from(this.context); + peertubeNotificationsListAdapter = this; + + } + + + @NonNull + @Override + public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + return new ViewHolder(layoutInflater.inflate(R.layout.drawer_notification, parent, false)); + } + + @Override + public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int position) { + + holder = (PeertubeNotificationsListAdapter.ViewHolder) viewHolder; + PeertubeNotification notification = notifications.get(position); + SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); + int theme = sharedpreferences.getInt(Helper.SET_THEME, Helper.THEME_DARK); + if (theme == THEME_DARK ){ + holder.main_container_trans.setBackgroundColor(ContextCompat.getColor(context, R.color.notif_dark_1)); + holder.main_container_trans.setAlpha(.5f); + }else if( theme == THEME_BLACK){ + holder.main_container_trans.setBackgroundColor(ContextCompat.getColor(context, R.color.notif_black_1)); + holder.main_container_trans.setAlpha(.5f); + }else{ + holder.main_container_trans.setBackgroundColor(ContextCompat.getColor(context, R.color.notif_light_1)); + holder.main_container_trans.setAlpha(.5f); + } + if (theme == Helper.THEME_DARK) { + style = R.style.DialogDark; + } else if (theme == Helper.THEME_BLACK){ + style = R.style.DialogBlack; + }else { + style = R.style.Dialog; + } + //Follow Notification + PeertubeAccountNotification accountAction = null; + PeertubeVideoNotification videoAction = null; + if( notification.getPeertubeActorFollow() != null){ + + Helper.loadGiF(context, notification.getPeertubeActorFollow().getFollower().getAvatar(), holder.peertube_notif_pp); + accountAction =notification.getPeertubeActorFollow().getFollower(); + String type = notification.getPeertubeActorFollow().getFollowing().getType(); + String message; + if( type.equals("account")){ + message = context.getString(R.string.peertube_follow_channel, accountAction.getDisplayName(), notification.getPeertubeActorFollow().getFollowing().getDisplayName()); + }else{ + message = context.getString(R.string.peertube_follow_account, accountAction.getDisplayName()); + } + holder.peertube_notif_message.setText(message); + PeertubeAccountNotification finalAccountAction1 = accountAction; + holder.peertube_notif_pp.setOnClickListener(v -> { + Intent intent = new Intent(context, ShowAccountActivity.class); + Bundle b = new Bundle(); + b.putBoolean("peertubeaccount", true); + b.putString("accountId", finalAccountAction1.getName()); + intent.putExtras(b); + context.startActivity(intent); + }); + }else if( notification.getPeertubeComment() != null){ //Comment Notification + Helper.loadGiF(context, notification.getPeertubeComment().getPeertubeAccountNotification().getAvatar(), holder.peertube_notif_pp); + accountAction = notification.getPeertubeComment().getPeertubeAccountNotification(); + videoAction = notification.getPeertubeComment().getPeertubeVideoNotification(); + holder.peertube_notif_message.setText(context.getString(R.string.peertube_comment_on_video,accountAction.getDisplayName(), videoAction.getName())); + PeertubeVideoNotification finalVideoAction1 = videoAction; + holder.peertube_notif_message.setOnClickListener(v -> { + Intent intent = new Intent(context, PeertubeActivity.class); + Bundle b = new Bundle(); + b.putString("video_id", finalVideoAction1.getUuid()); + intent.putExtras(b); + context.startActivity(intent); + }); + }else {//Other Notifications + if (notification.getPeertubeVideoNotification() != null && notification.getPeertubeVideoNotification().getPeertubeAccountNotification() != null){ + Helper.loadGiF(context, notification.getPeertubeVideoNotification().getPeertubeAccountNotification().getAvatar(), holder.peertube_notif_pp); + accountAction = notification.getPeertubeVideoNotification().getPeertubeAccountNotification(); + videoAction = notification.getPeertubeVideoNotification(); + String message = ""; + if (notification.getType() == DisplayPeertubeNotificationsFragment.MY_VIDEO_PUBLISHED){ + message = context.getString(R.string.peertube_video_published, videoAction.getName()); + }else if(notification.getType() == DisplayPeertubeNotificationsFragment.MY_VIDEO_IMPORT_ERROR){ + message = context.getString(R.string.peertube_video_import_error, videoAction.getName()); + }else if(notification.getType() == DisplayPeertubeNotificationsFragment.MY_VIDEO_IMPORT_SUCCESS){ + message = context.getString(R.string.peertube_video_import_success, videoAction.getName()); + }else if(notification.getType() == DisplayPeertubeNotificationsFragment.NEW_VIDEO_FROM_SUBSCRIPTION){ + message = context.getString(R.string.peertube_video_from_subscription, accountAction.getDisplayName(), videoAction.getName()); + }else if(notification.getType() == DisplayPeertubeNotificationsFragment.BLACKLIST_ON_MY_VIDEO){ + message = context.getString(R.string.peertube_video_blacklist, videoAction.getName()); + }else if(notification.getType() == DisplayPeertubeNotificationsFragment.UNBLACKLIST_ON_MY_VIDEO){ + message = context.getString(R.string.peertube_video_unblacklist, videoAction.getName()); + } + holder.peertube_notif_message.setText(message); + PeertubeVideoNotification finalVideoAction = videoAction; + holder.peertube_notif_message.setOnClickListener(v -> { + Intent intent = new Intent(context, PeertubeActivity.class); + Bundle b = new Bundle(); + b.putString("video_id", finalVideoAction.getUuid()); + intent.putExtras(b); + context.startActivity(intent); + }); + } + } + + PeertubeAccountNotification finalAccountAction = accountAction; + holder.peertube_notif_pp.setOnClickListener(v -> { + if( finalAccountAction != null){ + Intent intent = new Intent(context, ShowAccountActivity.class); + Bundle b = new Bundle(); + b.putBoolean("peertubeaccount", true); + b.putString("accountId", finalAccountAction.getName()); + intent.putExtras(b); + context.startActivity(intent); + } + }); + } + + private void notifyNotificationChanged(Notification notification){ + for (int i = 0; i < peertubeNotificationsListAdapter.getItemCount(); i++) { + if (peertubeNotificationsListAdapter.getItemAt(i) != null && peertubeNotificationsListAdapter.getItemAt(i).getId().equals(notification.getId())) { + try { + peertubeNotificationsListAdapter.notifyItemChanged(i); + } catch (Exception ignored) { } + } + } + } + + + + @Override + public long getItemId(int position) { + return position; + } + + @Override + public int getItemCount() { + return notifications.size(); + } + + + private PeertubeNotification getItemAt(int position){ + if( notifications.size() > position) + return notifications.get(position); + else + return null; + } + + + class ViewHolder extends RecyclerView.ViewHolder { + + ImageView peertube_notif_pp; + TextView peertube_notif_message, peertube_notif_date; + RelativeLayout main_container_trans; + public View getView(){ + return itemView; + } + + public ViewHolder(View itemView) { + super(itemView); + peertube_notif_pp = itemView.findViewById(R.id.peertube_notif_pp); + peertube_notif_message = itemView.findViewById(R.id.peertube_notif_message); + peertube_notif_date = itemView.findViewById(R.id.peertube_notif_date); + main_container_trans = itemView.findViewById(R.id.container_trans); + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/fragments/DisplayPeertubeNotificationsFragment.java b/app/src/main/java/fr/gouv/etalab/mastodon/fragments/DisplayPeertubeNotificationsFragment.java new file mode 100644 index 000000000..f4080a7fe --- /dev/null +++ b/app/src/main/java/fr/gouv/etalab/mastodon/fragments/DisplayPeertubeNotificationsFragment.java @@ -0,0 +1,433 @@ +package fr.gouv.etalab.mastodon.fragments; +/* Copyright 2019 Thomas Schneider + * + * This file is a part of Mastalab + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 3 of the + * License, or (at your option) any later version. + * + * Mastalab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along with Mastalab; if not, + * see . */ + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.SharedPreferences; +import android.os.AsyncTask; +import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; +import android.support.annotation.NonNull; +import android.support.v4.app.Fragment; +import android.support.v4.content.ContextCompat; +import android.support.v4.content.LocalBroadcastManager; +import android.support.v4.widget.SwipeRefreshLayout; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.RelativeLayout; +import android.widget.Toast; + +import java.util.ArrayList; +import java.util.List; + +import es.dmoral.toasty.Toasty; +import fr.gouv.etalab.mastodon.R; +import fr.gouv.etalab.mastodon.activities.MainActivity; +import fr.gouv.etalab.mastodon.asynctasks.RetrieveMissingNotificationsAsyncTask; +import fr.gouv.etalab.mastodon.asynctasks.RetrieveNotificationsAsyncTask; +import fr.gouv.etalab.mastodon.asynctasks.UpdateAccountInfoAsyncTask; +import fr.gouv.etalab.mastodon.client.API; +import fr.gouv.etalab.mastodon.client.APIResponse; +import fr.gouv.etalab.mastodon.client.Entities.Account; +import fr.gouv.etalab.mastodon.client.Entities.Notification; +import fr.gouv.etalab.mastodon.client.Entities.Status; +import fr.gouv.etalab.mastodon.drawers.NotificationsListAdapter; +import fr.gouv.etalab.mastodon.helper.Helper; +import fr.gouv.etalab.mastodon.interfaces.OnRetrieveMissingNotificationsInterface; +import fr.gouv.etalab.mastodon.interfaces.OnRetrieveNotificationsInterface; + + +/** + * Created by Thomas on 24/01/2019. + * Fragment to display peertube notifications + */ +public class DisplayPeertubeNotificationsFragment extends Fragment implements OnRetrieveNotificationsInterface, OnRetrieveMissingNotificationsInterface { + + + + private boolean flag_loading; + private Context context; + private AsyncTask asyncTask; + private NotificationsListAdapter notificationsListAdapter; + private String max_id; + private List notifications; + private RelativeLayout mainLoader, nextElementLoader, textviewNoAction; + private boolean firstLoad; + private SwipeRefreshLayout swipeRefreshLayout; + private boolean swiped; + private RecyclerView lv_notifications; + private String userId, instance; + private SharedPreferences sharedpreferences; + LinearLayoutManager mLayoutManager; + private BroadcastReceiver receive_action; + private BroadcastReceiver receive_data; + + //Peertube notification type + public static int NEW_VIDEO_FROM_SUBSCRIPTION = 1; + public static int NEW_COMMENT_ON_MY_VIDEO = 2; + public static int NEW_VIDEO_ABUSE_FOR_MODERATORS = 3; + public static int BLACKLIST_ON_MY_VIDEO = 4; + public static int UNBLACKLIST_ON_MY_VIDEO = 5; + public static int MY_VIDEO_PUBLISHED = 6; + public static int MY_VIDEO_IMPORT_SUCCESS = 7; + public static int MY_VIDEO_IMPORT_ERROR = 8; + public static int NEW_USER_REGISTRATION = 9; + public static int NEW_FOLLOW = 10; + public static int COMMENT_MENTION = 11; + + public DisplayPeertubeNotificationsFragment(){ + } + + @Override + public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + + View rootView = inflater.inflate(R.layout.fragment_notifications, container, false); + max_id = null; + context = getContext(); + firstLoad = true; + flag_loading = true; + notifications = new ArrayList<>(); + swiped = false; + swipeRefreshLayout = rootView.findViewById(R.id.swipeContainer); + sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); + + + lv_notifications = rootView.findViewById(R.id.lv_notifications); + mainLoader = rootView.findViewById(R.id.loader); + nextElementLoader = rootView.findViewById(R.id.loading_next_notifications); + textviewNoAction = rootView.findViewById(R.id.no_action); + mainLoader.setVisibility(View.VISIBLE); + nextElementLoader.setVisibility(View.GONE); + boolean isOnWifi = Helper.isOnWIFI(context); + int behaviorWithAttachments = sharedpreferences.getInt(Helper.SET_ATTACHMENT_ACTION, Helper.ATTACHMENT_ALWAYS); + userId = sharedpreferences.getString(Helper.PREF_KEY_ID, null); + instance = sharedpreferences.getString(Helper.PREF_INSTANCE, context!=null?Helper.getLiveInstance(context):null); + notificationsListAdapter = new NotificationsListAdapter(context,isOnWifi, behaviorWithAttachments,this.notifications); + lv_notifications.setAdapter(notificationsListAdapter); + mLayoutManager = new LinearLayoutManager(context); + lv_notifications.setLayoutManager(mLayoutManager); + lv_notifications.addOnScrollListener(new RecyclerView.OnScrollListener() { + public void onScrolled(RecyclerView recyclerView, int dx, int dy) + { + if(dy > 0) { + int visibleItemCount = mLayoutManager.getChildCount(); + int totalItemCount = mLayoutManager.getItemCount(); + int firstVisibleItem = mLayoutManager.findFirstVisibleItemPosition(); + if (firstVisibleItem + visibleItemCount == totalItemCount && context != null) { + if (!flag_loading) { + flag_loading = true; + asyncTask = new RetrieveNotificationsAsyncTask(context, true, null, max_id, DisplayPeertubeNotificationsFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + nextElementLoader.setVisibility(View.VISIBLE); + } + } else { + nextElementLoader.setVisibility(View.GONE); + } + } + } + }); + + if( MainActivity.social == UpdateAccountInfoAsyncTask.SOCIAL.MASTODON) { + + if( receive_action != null) + LocalBroadcastManager.getInstance(context).unregisterReceiver(receive_action); + receive_action = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + Bundle b = intent.getExtras(); + assert b != null; + Status status = b.getParcelable("status"); + API.StatusAction statusAction = (API.StatusAction) b.getSerializable("action"); + if( status != null) { + notificationsListAdapter.notifyNotificationWithActionChanged(statusAction, status); + } + } + }; + LocalBroadcastManager.getInstance(context).registerReceiver(receive_action, new IntentFilter(Helper.RECEIVE_ACTION)); + + if( receive_data != null) + LocalBroadcastManager.getInstance(context).unregisterReceiver(receive_data); + receive_data = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + Bundle b = intent.getExtras(); + assert b != null; + String userIdService = b.getString("userIdService", null); + if( userIdService != null && userIdService.equals(userId)) { + Notification notification = b.getParcelable("data"); + refresh(notification); + if( context instanceof MainActivity) + ((MainActivity)context).updateNotifCounter(); + } + } + }; + LocalBroadcastManager.getInstance(context).registerReceiver(receive_data, new IntentFilter(Helper.RECEIVE_DATA)); + } + + swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { + @Override + public void onRefresh() { + max_id = null; + firstLoad = true; + flag_loading = true; + swiped = true; + MainActivity.countNewNotifications = 0; + try { + ((MainActivity) context).updateNotifCounter(); + }catch (Exception ignored){} + String sinceId = null; + if( notifications != null && notifications.size() > 0 ) + sinceId = notifications.get(0).getId(); + if( context != null) + asyncTask = new RetrieveMissingNotificationsAsyncTask(context, sinceId, DisplayPeertubeNotificationsFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + } + }); + SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); + int theme = sharedpreferences.getInt(Helper.SET_THEME, Helper.THEME_DARK); + switch (theme){ + case Helper.THEME_LIGHT: + swipeRefreshLayout.setColorSchemeResources(R.color.mastodonC4, + R.color.mastodonC2, + R.color.mastodonC3); + swipeRefreshLayout.setProgressBackgroundColorSchemeColor(ContextCompat.getColor(context, R.color.white)); + break; + case Helper.THEME_DARK: + swipeRefreshLayout.setColorSchemeResources(R.color.mastodonC4__, + R.color.mastodonC4, + R.color.mastodonC4); + swipeRefreshLayout.setProgressBackgroundColorSchemeColor(ContextCompat.getColor(context, R.color.mastodonC1_)); + break; + case Helper.THEME_BLACK: + swipeRefreshLayout.setColorSchemeResources(R.color.dark_icon, + R.color.mastodonC2, + R.color.mastodonC3); + swipeRefreshLayout.setProgressBackgroundColorSchemeColor(ContextCompat.getColor(context, R.color.black_3)); + break; + } + if( context != null) + asyncTask = new RetrieveNotificationsAsyncTask(context, true, null, max_id, DisplayPeertubeNotificationsFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + else + new Handler(Looper.getMainLooper()).postDelayed(new Runnable() { + @Override + public void run() { + if( context != null) + asyncTask = new RetrieveNotificationsAsyncTask(context, true, null, max_id, DisplayPeertubeNotificationsFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + } + }, 500); + return rootView; + } + + + + @Override + public void onCreate(Bundle saveInstance) + { + super.onCreate(saveInstance); + } + + + + @Override + public void onAttach(Context context) { + super.onAttach(context); + this.context = context; + } + + public void onDestroy() { + super.onDestroy(); + if(asyncTask != null && asyncTask.getStatus() == AsyncTask.Status.RUNNING) + asyncTask.cancel(true); + if( receive_action != null) + LocalBroadcastManager.getInstance(context).unregisterReceiver(receive_action); + if( receive_data != null) + LocalBroadcastManager.getInstance(context).unregisterReceiver(receive_data); + + } + + @Override + public void onRetrieveNotifications(APIResponse apiResponse, Account account, boolean refreshData) { + mainLoader.setVisibility(View.GONE); + nextElementLoader.setVisibility(View.GONE); + String lastReadNotifications = sharedpreferences.getString(Helper.LAST_NOTIFICATION_MAX_ID + userId + instance, null); + if( apiResponse.getError() != null){ + Toasty.error(context, apiResponse.getError().getError(),Toast.LENGTH_LONG).show(); + flag_loading = false; + swipeRefreshLayout.setRefreshing(false); + swiped = false; + return; + } + + int previousPosition = notifications.size(); + max_id = apiResponse.getMax_id(); + List notifications = apiResponse.getNotifications(); + + if( !swiped && firstLoad && (notifications == null || notifications.size() == 0)) + textviewNoAction.setVisibility(View.VISIBLE); + else + textviewNoAction.setVisibility(View.GONE); + if( swiped ){ + if (previousPosition > 0) { + for (int i = 0; i < previousPosition; i++) { + this.notifications.remove(0); + } + notificationsListAdapter.notifyItemRangeRemoved(0, previousPosition); + } + swiped = false; + } + + if( notifications != null && notifications.size() > 0) { + for(Notification tmpNotification: notifications){ + + if( lastReadNotifications != null && Long.parseLong(tmpNotification.getId()) > Long.parseLong(lastReadNotifications)) { + MainActivity.countNewNotifications++; + } + try { + ((MainActivity) context).updateNotifCounter(); + }catch (Exception ignored){} + this.notifications.add(tmpNotification); + } + if( firstLoad) { + //Update the id of the last notification retrieved + if( MainActivity.lastNotificationId == null || Long.parseLong(notifications.get(0).getId()) > Long.parseLong(MainActivity.lastNotificationId)) + MainActivity.lastNotificationId = notifications.get(0).getId(); + updateNotificationLastId(notifications.get(0).getId()); + } + notificationsListAdapter.notifyItemRangeInserted(previousPosition, notifications.size()); + }else { + if( firstLoad) + textviewNoAction.setVisibility(View.VISIBLE); + } + if( firstLoad ) + ((MainActivity)context).updateNotifCounter(); + swipeRefreshLayout.setRefreshing(false); + firstLoad = false; + //The initial call comes from a classic tab refresh + flag_loading = (max_id == null ); + } + + /** + * Called from main activity in onResume to retrieve missing notifications + * @param sinceId String + */ + public void retrieveMissingNotifications(String sinceId){ + asyncTask = new RetrieveMissingNotificationsAsyncTask(context, sinceId, DisplayPeertubeNotificationsFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + } + + @Override + public void setMenuVisibility(final boolean visible) { + super.setMenuVisibility(visible); + if( context == null) + return; + //Store last notification id to avoid to notify for those that have been already seen + if (visible && notifications != null && notifications.size() > 0) { + retrieveMissingNotifications(notifications.get(0).getId()); + updateNotificationLastId(notifications.get(0).getId()); + } + } + + public void scrollToTop(){ + if( lv_notifications != null) + lv_notifications.setAdapter(notificationsListAdapter); + //Store last toot id for home timeline to avoid to notify for those that have been already seen + if (this.notifications != null && this.notifications.size() > 0) { + updateNotificationLastId(this.notifications.get(0).getId()); + } + } + + public void refreshAll(){ + if( context == null) + return; + max_id = null; + firstLoad = true; + flag_loading = true; + swiped = true; + MainActivity.countNewNotifications = 0; + asyncTask = new RetrieveNotificationsAsyncTask(context, true, null, null, DisplayPeertubeNotificationsFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + } + + + public void refresh(Notification notification){ + if( context == null) + return; + if( notification != null){ + //Makes sure the notifications is not already displayed + if( !this.notifications.contains(notification)) { + //Update the id of the last notification retrieved + MainActivity.lastNotificationId = notification.getId(); + notifications.add(0, notification); + MainActivity.countNewNotifications++; + try { + ((MainActivity) context).updateNotifCounter(); + }catch (Exception ignored){} + int firstVisibleItem = mLayoutManager.findFirstVisibleItemPosition(); + if (firstVisibleItem > 0) + notificationsListAdapter.notifyItemInserted(0); + else + notificationsListAdapter.notifyDataSetChanged(); + if (textviewNoAction.getVisibility() == View.VISIBLE) + textviewNoAction.setVisibility(View.GONE); + } + } + } + + + + @Override + public void onRetrieveMissingNotifications(List notifications) { + flag_loading = false; + swipeRefreshLayout.setRefreshing(false); + if( this.notifications != null && this.notifications.size() > 0){ + notificationsListAdapter.notifyItemRangeChanged(0,this.notifications.size()); + } + if( notifications != null && notifications.size() > 0) { + int inserted = 0; + for (int i = notifications.size()-1 ; i >= 0 ; i--) { + if (this.notifications != null && this.notifications.size() == 0 || + Long.parseLong(notifications.get(i).getId()) > Long.parseLong(this.notifications.get(0).getId())) { + MainActivity.countNewNotifications++; + this.notifications.add(0, notifications.get(i)); + inserted++; + } + } + notificationsListAdapter.notifyItemRangeInserted(0,inserted); + try { + ((MainActivity) context).updateNotifCounter(); + }catch (Exception ignored){} + } + } + + + + /** + * Records the id of the notification only if its greater than the previous one. + * @param notificationId String current notification id to check + */ + private void updateNotificationLastId(String notificationId){ + + String lastNotif = sharedpreferences.getString(Helper.LAST_NOTIFICATION_MAX_ID + userId + instance, null); + if( lastNotif == null || Long.parseLong(notificationId) > Long.parseLong(lastNotif)){ + MainActivity.countNewNotifications = 0; + SharedPreferences.Editor editor = sharedpreferences.edit(); + editor.putString(Helper.LAST_NOTIFICATION_MAX_ID + userId + instance, notificationId); + editor.apply(); + } + } +} diff --git a/app/src/main/res/drawable-anydpi/ic_notifications_peertube.xml b/app/src/main/res/drawable-anydpi/ic_notifications_peertube.xml new file mode 100644 index 000000000..7009a6763 --- /dev/null +++ b/app/src/main/res/drawable-anydpi/ic_notifications_peertube.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/layout/drawer_peertube_notification.xml b/app/src/main/res/layout/drawer_peertube_notification.xml new file mode 100644 index 000000000..bfa276bb9 --- /dev/null +++ b/app/src/main/res/layout/drawer_peertube_notification.xml @@ -0,0 +1,61 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/activity_main_drawer.xml b/app/src/main/res/menu/activity_main_drawer.xml index 347e4a043..dcec71c92 100644 --- a/app/src/main/res/menu/activity_main_drawer.xml +++ b/app/src/main/res/menu/activity_main_drawer.xml @@ -70,6 +70,10 @@ android:id="@+id/nav_upload" android:icon="@drawable/ic_cloud_upload" android:title="@string/upload_video" /> + Hidden content Composing Contacts + %1$s commented your video %2$s + %1$s is following your channel %2$s + %1$s is following your account + + Your video %1$s has been published + Your video import %1$s succeeded + Your video import %1$s failed + %1$s published a new video: %2$s + Your video %1$s has been blacklisted + Your video %1$s has been unblacklisted