Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add message reply based on contacts #316

Merged
merged 4 commits into from
Jun 8, 2021
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
8 changes: 8 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-permission android:name="android.permission.READ_CONTACTS" />

<queries>
<!-- Specific apps Watomatic interacts with. Required for Android 11+ -->
Expand Down Expand Up @@ -55,6 +56,13 @@
>
</activity>

<activity
android:name="com.parishod.watomatic.activity.advancedsettings.AdvancedSettingsActivity"
android:label="@string/advanced_settings"
android:parentActivityName="com.parishod.watomatic.activity.settings.SettingsActivity"
>
</activity>

<activity
android:name="com.parishod.watomatic.activity.notification.NotificationIntentActivity"
android:launchMode="singleTop"
Expand Down
32 changes: 28 additions & 4 deletions app/src/main/java/com/parishod/watomatic/NotificationService.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@

import com.parishod.watomatic.model.CustomRepliesData;
import com.parishod.watomatic.model.preferences.PreferencesManager;
import com.parishod.watomatic.model.utils.Constants;
import com.parishod.watomatic.model.utils.DbUtils;
import com.parishod.watomatic.model.utils.NotificationHelper;
import com.parishod.watomatic.model.utils.NotificationUtils;
Expand All @@ -27,7 +26,7 @@ public class NotificationService extends NotificationListenerService {
@Override
public void onNotificationPosted(StatusBarNotification sbn) {
super.onNotificationPosted(sbn);
if(canReply(sbn)) {
if(canReply(sbn) && shouldReply(sbn)) {
sendReply(sbn);
}
}
Expand All @@ -40,6 +39,32 @@ private boolean canReply(StatusBarNotification sbn){
canSendReplyNow(sbn);
}

private boolean shouldReply(StatusBarNotification sbn){
PreferencesManager prefs = PreferencesManager.getPreferencesInstance(this);
boolean isGroup = sbn.getNotification().extras.getBoolean("android.isGroupConversation");
Copy link
Owner

@adeekshith adeekshith Jun 8, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Everything is good except group detection. This should work ideally but there is an issue where images messages in WhatsApp group are not being tagged with isGroupConversation sometimes (#181).

So there is an extra logic to detect that: src

May be we should move that logic to a separate method and reuse it.
Or I will merge this PR as is this evening and raise another one fixing this.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried using that logic, but didn't manage to do it right, so went the easy way as a temporary fix.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've read the issue you mentioned, if we are gonna add a new option to do extra checks in settings, i think this should be changed on the new PR

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No probs 😊
I'll merge this PR in the evening (CST) as is and make that fix before I forget. Great work!! 🙌

Also, as you are already good with Kotlin, feel free to use that in the future (anything is fine though). I am planning to move this project to Kotlin in the near future anyways as it is getting difficult to stick to Java in the Android world.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've read the issue you mentioned, if we are gonna add a new option to do extra checks in settings, i think this should be changed on the new PR

Yep, Had to do a hotfix for a previous release. As soon as that is done, will make a PR to fix this group issue.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No probs blush
I'll merge this PR in the evening (CST) as is and make that fix before I forget. Great work!! raised_hands

Sounds nice

Also, as you are already good with Kotlin, feel free to use that in the future (anything is fine though). I am planning to move this project to Kotlin in the near future anyways as it is getting difficult to stick to Java in the Android world.

Yay!


//Check contact based replies
if (prefs.isContactReplyEnabled() && !isGroup) {
//Title contains sender name (at least on WhatsApp)
String senderName = sbn.getNotification().extras.getString("android.title");
//Check if should reply to contact
boolean isNameSelected = prefs.getReplyToNames().contains(senderName);
if ((isNameSelected && prefs.isContactReplyBlacklistMode()) ||
!isNameSelected && !prefs.isContactReplyBlacklistMode()) {
//If contact is on the list and contact reply is on blacklist mode,
// or contact is not in the list and reply is on whitelist mode,
// we don't want to reply

return false;
}
}

//Check more conditions on future feature implementations

//If we got here, all conditions to reply are met
return true;
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
Expand All @@ -53,7 +78,6 @@ private void sendReply(StatusBarNotification sbn) {
// "Checking for new messages" or "WhatsApp web is Active"
if (notificationWear.getRemoteInputs().isEmpty()) { return;}


customRepliesData = CustomRepliesData.getInstance(this);

RemoteInput[] remoteInputs = new RemoteInput[notificationWear.getRemoteInputs().size()];
Expand Down Expand Up @@ -92,7 +116,7 @@ private void sendReply(StatusBarNotification sbn) {
}

private boolean canPurgeMessages() {
//Added L to avoind numeric overflow expression
//Added L to avoid numeric overflow expression
//https://stackoverflow.com/questions/43801874/numeric-overflow-in-expression-manipulating-timestamps
long daysBeforePurgeInMS = 30 * 24 * 60 * 60 * 1000L;
return (System.currentTimeMillis() - PreferencesManager.getPreferencesInstance(this).getLastPurgedTime()) > daysBeforePurgeInMS;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.parishod.watomatic.activity.advancedsettings;

import android.os.Bundle;

import com.parishod.watomatic.R;
import com.parishod.watomatic.activity.BaseActivity;

public class AdvancedSettingsActivity extends BaseActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_advanced_settings);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package com.parishod.watomatic.fragment;

import android.os.Build;
import android.os.Bundle;

import androidx.preference.Preference;
import androidx.preference.PreferenceFragmentCompat;
import androidx.preference.SwitchPreference;

import com.parishod.watomatic.R;
import com.parishod.watomatic.model.utils.ContactsHelper;

public class AdvancedSettingsFragment extends PreferenceFragmentCompat {

private Preference advancedPref;
private SwitchPreference enable_contact_replies_preference;
private ContactsHelper contactsHelper;

@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
setPreferencesFromResource(R.xml.fragment_advanced_settings, rootKey);

contactsHelper = ContactsHelper.getInstance(getContext());

enable_contact_replies_preference = findPreference(getString(R.string.pref_reply_contacts));
enable_contact_replies_preference.setOnPreferenceChangeListener((preference, newValue) -> {
if ((Boolean) newValue) {
if (contactsHelper.hasContactPermission())
return true;
else {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
contactsHelper.requestContactPermission(getActivity());
}
return false;
}
}
return true;
});

advancedPref = findPreference(getString(R.string.key_pref_select_contacts));
advancedPref.setOnPreferenceClickListener(preference -> {
if (contactsHelper.hasContactPermission())
contactsHelper.showContactPicker();
else {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
contactsHelper.requestContactPermission(getActivity());
}
}
return true;
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,16 @@
import androidx.preference.SwitchPreference;

import com.parishod.watomatic.R;
import com.parishod.watomatic.activity.advancedsettings.AdvancedSettingsActivity;
import com.parishod.watomatic.activity.customreplyeditor.CustomReplyEditorActivity;
import com.parishod.watomatic.activity.main.MainActivity;
import com.parishod.watomatic.model.preferences.PreferencesManager;
import com.parishod.watomatic.model.utils.AutoStartHelper;

public class SettingsFragment extends PreferenceFragmentCompat {
private ListPreference languagePref;
private SwitchPreference showNotificationPref;
private Preference advancedPref;
private Preference autoStartPref;

@Override
Expand Down Expand Up @@ -49,6 +52,16 @@ public boolean onPreferenceClick(Preference preference) {
return true;
}
});

advancedPref = findPreference(getString(R.string.key_pref_advanced_settings));
advancedPref.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
Intent advancedSettings = new Intent(getActivity(), AdvancedSettingsActivity.class);
getActivity().startActivity(advancedSettings);
return false;
}
});
}

private void checkAutoStartPermission() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,13 +116,11 @@ public String getOrElse(String defaultText) {
}

public String getTextToSendOrElse (String defaultTextToSend) {
String currentText = get();
String currentText = getOrElse(thisAppContext.getString(R.string.auto_reply_default_message));
if (preferencesManager.isAppendWatomaticAttributionEnabled()) {
currentText += "\n\n"+ RTL_ALIGN_INVISIBLE_CHAR + thisAppContext.getString(R.string.sent_using_Watomatic);
}
return (currentText != null)
? currentText
: defaultTextToSend;
return currentText;
hegocre marked this conversation as resolved.
Show resolved Hide resolved
}

private JSONArray getAll() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package com.parishod.watomatic.model.adapters;

import android.view.LayoutInflater;
import android.view.ViewGroup;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

import com.parishod.watomatic.databinding.ContactListRowBinding;
import com.parishod.watomatic.model.data.ContactHolder;

import org.jetbrains.annotations.NotNull;

import java.util.ArrayList;

public class ContactListAdapter extends RecyclerView.Adapter<ContactListAdapter.ViewHolder> {
private final ArrayList<ContactHolder> contactHolderArrayList;

public ContactListAdapter(ArrayList<ContactHolder> contactHolderArrayList) {
this.contactHolderArrayList = contactHolderArrayList;
}

@NonNull
@NotNull
@Override
public ViewHolder onCreateViewHolder(@NonNull @NotNull ViewGroup parent, int viewType) {
ContactListRowBinding binding = ContactListRowBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false);
return new ViewHolder(binding);
}

@Override
public void onBindViewHolder(@NonNull @NotNull ViewHolder holder, int position) {
ContactListRowBinding binding = holder.getBinding();
binding.contactCheckbox.setChecked(contactHolderArrayList.get(position).isChecked());
binding.contactCheckbox.setText(contactHolderArrayList.get(position).getContactName());
binding.contactCheckbox.setOnCheckedChangeListener((buttonView, isChecked) ->
contactHolderArrayList.get(position).setChecked(isChecked));
}

@Override
public void onViewRecycled(@NonNull @NotNull ViewHolder holder) {
ContactListRowBinding binding = holder.getBinding();
binding.contactCheckbox.setOnCheckedChangeListener(null);
super.onViewRecycled(holder);
}

@Override
public int getItemCount() {
return contactHolderArrayList.size();
}

@Override
public long getItemId(int position) {
return position;
}

class ViewHolder extends RecyclerView.ViewHolder {
private final ContactListRowBinding binding;
public ViewHolder(@NonNull @NotNull ContactListRowBinding binding) {
super(binding.getRoot());
this.binding = binding;
}

public ContactListRowBinding getBinding() {
return binding;
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.parishod.watomatic.model.data;

public class ContactHolder {
private final String contactName;
private boolean isChecked;

public ContactHolder(String contactName, boolean isChecked) {
this.contactName = contactName;
this.isChecked = isChecked;
}

public String getContactName() {
return contactName;
}

public void setChecked(boolean checked) {
isChecked = checked;
}

public boolean isChecked() {
return isChecked;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ public class PreferencesManager {
private final String KEY_PURGE_MESSAGE_LOGS_LAST_TIME = "pref_purge_message_logs_last_time";
private final String KEY_PLAY_STORE_RATING_STATUS = "pref_play_store_rating_status";
private final String KEY_PLAY_STORE_RATING_LAST_TIME = "pref_play_store_rating_last_time";
private final String KEY_REPLY_CONTACTS = "pref_reply_contacts";
private final String KEY_REPLY_CONTACTS_TYPE = "pref_reply_contacts_type";
private final String KEY_SELECTED_CONTACT_NAMES = "pref_selected_contacts_names";
private String KEY_IS_SHOW_NOTIFICATIONS_ENABLED;
private String KEY_SELECTED_APP_LANGUAGE;
private static PreferencesManager _instance;
Expand Down Expand Up @@ -269,4 +272,23 @@ public void setPlayStoreRatingLastTime(long purgeMessageTime){
editor.putLong(KEY_PLAY_STORE_RATING_LAST_TIME, purgeMessageTime);
editor.apply();
}

public void setReplyToNames(Set<String> names) {
SharedPreferences.Editor editor = _sharedPrefs.edit();
editor.putStringSet(KEY_SELECTED_CONTACT_NAMES, names);
editor.apply();
}

public Set<String> getReplyToNames() {
return _sharedPrefs.getStringSet(KEY_SELECTED_CONTACT_NAMES, new HashSet<>());
}

public boolean isContactReplyEnabled() {
return _sharedPrefs.getBoolean(KEY_REPLY_CONTACTS, false);
}

public Boolean isContactReplyBlacklistMode() {
return _sharedPrefs.getString(KEY_REPLY_CONTACTS_TYPE, "pref_blacklist").equals("pref_blacklist");
}

}
Loading