Add basic call log
This commit is contained in:
parent
b1b5c7c731
commit
3f6778cbc7
|
@ -31,9 +31,8 @@ dependencies {
|
|||
implementation 'com.squareup.okhttp3:okhttp:3.12.11'
|
||||
implementation 'commons-codec:commons-codec:1.14' // beware: a version included in Android is used instead
|
||||
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
implementation 'androidx.appcompat:appcompat:1.1.0'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
|
||||
implementation 'androidx.recyclerview:recyclerview:1.1.0'
|
||||
implementation 'com.google.android.material:material:1.1.0'
|
||||
implementation 'androidx.work:work-runtime:2.3.4'
|
||||
}
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
package dummydomain.yetanothercallblocker;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.provider.CallLog;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class CallLogHelper {
|
||||
|
||||
private static final String[] QUERY_PROJECTION = new String[]{
|
||||
CallLog.Calls.TYPE, CallLog.Calls.NUMBER, CallLog.Calls.DATE, CallLog.Calls.DURATION
|
||||
};
|
||||
|
||||
public static List<CallLogItem> getRecentCalls(Context context, int num) {
|
||||
List<CallLogItem> logItems = new ArrayList<>(num);
|
||||
|
||||
try (Cursor cursor = context.getContentResolver().query(CallLog.Calls.CONTENT_URI,
|
||||
QUERY_PROJECTION, null, null, CallLog.Calls.DEFAULT_SORT_ORDER)) {
|
||||
if (cursor != null) {
|
||||
int typeIndex = cursor.getColumnIndex(CallLog.Calls.TYPE);
|
||||
int numberIndex = cursor.getColumnIndex(CallLog.Calls.NUMBER);
|
||||
int dateIndex = cursor.getColumnIndex(CallLog.Calls.DATE);
|
||||
int durationIndex = cursor.getColumnIndex(CallLog.Calls.DURATION);
|
||||
|
||||
while (cursor.moveToNext() && logItems.size() < num) {
|
||||
int callType = cursor.getInt(typeIndex);
|
||||
String number = cursor.getString(numberIndex);
|
||||
long callDate = cursor.getLong(dateIndex);
|
||||
long callDuration = cursor.getLong(durationIndex);
|
||||
|
||||
logItems.add(new CallLogItem(CallLogItem.Type.fromProviderType(callType),
|
||||
number, callDate, callDuration));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return logItems;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
package dummydomain.yetanothercallblocker;
|
||||
|
||||
import android.provider.CallLog;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import dummydomain.yetanothercallblocker.sia.model.NumberInfo;
|
||||
|
||||
public class CallLogItem {
|
||||
|
||||
public enum Type {
|
||||
INCOMING, OUTGOING, MISSED, REJECTED, OTHER;
|
||||
|
||||
public static Type fromProviderType(int type) {
|
||||
switch (type) {
|
||||
case CallLog.Calls.INCOMING_TYPE: return INCOMING;
|
||||
case CallLog.Calls.OUTGOING_TYPE: return OUTGOING;
|
||||
case CallLog.Calls.MISSED_TYPE: return MISSED;
|
||||
case CallLog.Calls.REJECTED_TYPE: return REJECTED;
|
||||
default: return OTHER;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Type type;
|
||||
public String number;
|
||||
public long timestamp;
|
||||
public long duration;
|
||||
public NumberInfo numberInfo;
|
||||
|
||||
public CallLogItem(Type type, String number, long timestamp, long duration) {
|
||||
Objects.requireNonNull(type);
|
||||
Objects.requireNonNull(number);
|
||||
this.type = type;
|
||||
this.number = number;
|
||||
this.timestamp = timestamp;
|
||||
this.duration = duration;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,120 @@
|
|||
package dummydomain.yetanothercallblocker;
|
||||
|
||||
import android.text.format.DateUtils;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.widget.AppCompatImageView;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class CallLogItemRecyclerViewAdapter
|
||||
extends RecyclerView.Adapter<CallLogItemRecyclerViewAdapter.ViewHolder> {
|
||||
|
||||
public interface OnListInteractionListener {
|
||||
void onListFragmentInteraction(CallLogItem item);
|
||||
}
|
||||
|
||||
private final List<CallLogItem> items;
|
||||
private final @Nullable OnListInteractionListener listener;
|
||||
|
||||
public CallLogItemRecyclerViewAdapter(List<CallLogItem> items,
|
||||
@Nullable OnListInteractionListener listener) {
|
||||
this.items = items;
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
View view = LayoutInflater.from(parent.getContext())
|
||||
.inflate(R.layout.call_log_item, parent, false);
|
||||
return new ViewHolder(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull final ViewHolder holder, int position) {
|
||||
holder.bind(items.get(position));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return items.size();
|
||||
}
|
||||
|
||||
private void onClick(int index) {
|
||||
if (index != RecyclerView.NO_POSITION && listener != null) {
|
||||
listener.onListFragmentInteraction(items.get(index));
|
||||
}
|
||||
}
|
||||
|
||||
class ViewHolder extends RecyclerView.ViewHolder {
|
||||
final View view;
|
||||
|
||||
final AppCompatImageView callTypeIcon;
|
||||
final TextView number;
|
||||
final AppCompatImageView numberInfoIcon;
|
||||
final TextView time;
|
||||
|
||||
ViewHolder(View view) {
|
||||
super(view);
|
||||
|
||||
this.view = view;
|
||||
|
||||
callTypeIcon = view.findViewById(R.id.callTypeIcon);
|
||||
number = view.findViewById(R.id.item_number);
|
||||
numberInfoIcon = view.findViewById(R.id.numberInfoIcon);
|
||||
time = view.findViewById(R.id.time);
|
||||
|
||||
view.setOnClickListener(v -> onClick(getAdapterPosition()));
|
||||
}
|
||||
|
||||
void bind(CallLogItem item) {
|
||||
Integer icon;
|
||||
switch (item.type) {
|
||||
case INCOMING:
|
||||
icon = R.drawable.ic_call_received_24dp;
|
||||
break;
|
||||
|
||||
case OUTGOING:
|
||||
icon = R.drawable.ic_call_made_24dp;
|
||||
break;
|
||||
|
||||
case MISSED:
|
||||
case REJECTED:
|
||||
icon = R.drawable.ic_call_missed_24dp;
|
||||
break;
|
||||
|
||||
default:
|
||||
icon = null;
|
||||
break;
|
||||
}
|
||||
if (icon != null) {
|
||||
callTypeIcon.setImageResource(icon);
|
||||
} else {
|
||||
callTypeIcon.setImageDrawable(null);
|
||||
}
|
||||
|
||||
number.setText(item.number);
|
||||
|
||||
IconAndColor iconAndColor = IconAndColor.forNumberRating(item.numberInfo.rating);
|
||||
if (!iconAndColor.noInfo) {
|
||||
iconAndColor.setOnImageView(numberInfoIcon);
|
||||
} else {
|
||||
numberInfoIcon.setImageDrawable(null);
|
||||
}
|
||||
|
||||
time.setText(DateUtils.getRelativeTimeSpanString(item.timestamp));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.toString() + " '" + number.getText() + "'";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,21 +1,19 @@
|
|||
package dummydomain.yetanothercallblocker;
|
||||
|
||||
import android.content.res.ColorStateList;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.widget.ImageViewCompat;
|
||||
import androidx.appcompat.widget.AppCompatImageView;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import android.text.TextUtils;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.widget.AppCompatImageView;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import dummydomain.yetanothercallblocker.sia.model.CommunityReview;
|
||||
import dummydomain.yetanothercallblocker.sia.model.NumberRating;
|
||||
|
||||
class CustomListViewAdapter extends RecyclerView.Adapter<CustomListViewAdapter.CommunityReviewViewHolder> {
|
||||
|
||||
|
@ -73,23 +71,7 @@ class CustomListViewAdapter extends RecyclerView.Adapter<CustomListViewAdapter.C
|
|||
tvDescription.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
IconAndColor iconAndColor = getRatingIconData(item.getRating());
|
||||
ivRating.setImageResource(iconAndColor.getIconResId());
|
||||
ImageViewCompat.setImageTintList(ivRating, ColorStateList.valueOf(
|
||||
itemView.getContext().getResources().getColor(iconAndColor.getColorResId())));
|
||||
}
|
||||
|
||||
protected IconAndColor getRatingIconData(NumberRating rating) {
|
||||
switch (rating) {
|
||||
case NEUTRAL:
|
||||
case UNKNOWN:
|
||||
return IconAndColor.of(R.drawable.ic_thumbs_up_down_black_24dp, R.color.rateNeutral);
|
||||
case POSITIVE:
|
||||
return IconAndColor.of(R.drawable.ic_thumb_up_black_24dp, R.color.ratePositive);
|
||||
case NEGATIVE:
|
||||
return IconAndColor.of(R.drawable.ic_thumb_down_black_24dp, R.color.rateNegative);
|
||||
}
|
||||
return IconAndColor.of(R.drawable.ic_thumbs_up_down_black_24dp, R.color.notFound);
|
||||
IconAndColor.forNumberRating(item.getRating()).setOnImageView(ivRating);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,13 +2,11 @@ package dummydomain.yetanothercallblocker;
|
|||
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import android.view.View;
|
||||
import android.widget.EditText;
|
||||
import android.widget.TextView;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import dummydomain.yetanothercallblocker.sia.DatabaseSingleton;
|
||||
import dummydomain.yetanothercallblocker.sia.model.NumberCategory;
|
||||
|
@ -121,17 +119,7 @@ public class DebugActivity extends AppCompatActivity {
|
|||
}
|
||||
|
||||
private void displaySummary(CommunityDatabaseItem item) {
|
||||
View summary = DebugActivity.this.findViewById(R.id.reviews_summary);
|
||||
summary.setVisibility(View.VISIBLE);
|
||||
|
||||
Map<Integer, Integer> map = new HashMap<>();
|
||||
map.put(R.id.summary_text_negative, item.getNegativeRatingsCount());
|
||||
map.put(R.id.summary_text_neutral, item.getNeutralRatingsCount());
|
||||
map.put(R.id.summary_text_positive, item.getPositiveRatingsCount());
|
||||
for (Map.Entry<Integer, Integer> e: map.entrySet()) {
|
||||
((TextView) summary.findViewById(e.getKey())).setText(
|
||||
String.valueOf(e.getValue()));
|
||||
}
|
||||
ReviewsSummaryHelper.populateSummary(findViewById(R.id.reviews_summary), item);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,23 +1,66 @@
|
|||
package dummydomain.yetanothercallblocker;
|
||||
|
||||
class IconAndColor {
|
||||
private int iconResId;
|
||||
private int colorResId;
|
||||
import android.content.res.ColorStateList;
|
||||
|
||||
public IconAndColor(int icon, int color) {
|
||||
this.iconResId = icon;
|
||||
this.colorResId = color;
|
||||
import androidx.annotation.ColorRes;
|
||||
import androidx.annotation.DrawableRes;
|
||||
import androidx.appcompat.widget.AppCompatImageView;
|
||||
import androidx.core.widget.ImageViewCompat;
|
||||
|
||||
import dummydomain.yetanothercallblocker.sia.model.NumberInfo;
|
||||
import dummydomain.yetanothercallblocker.sia.model.NumberRating;
|
||||
|
||||
class IconAndColor {
|
||||
|
||||
@DrawableRes
|
||||
final int iconResId;
|
||||
@ColorRes
|
||||
final int colorResId;
|
||||
final boolean noInfo;
|
||||
|
||||
private IconAndColor(int iconResId, int colorResId) {
|
||||
this(iconResId, colorResId, false);
|
||||
}
|
||||
|
||||
static IconAndColor of(int icon, int color) {
|
||||
private IconAndColor(int icon, int color, boolean noInfo) {
|
||||
this.iconResId = icon;
|
||||
this.colorResId = color;
|
||||
this.noInfo = noInfo;
|
||||
}
|
||||
|
||||
void setOnImageView(AppCompatImageView imageView) {
|
||||
imageView.setImageResource(iconResId);
|
||||
ImageViewCompat.setImageTintList(imageView, ColorStateList.valueOf(
|
||||
imageView.getContext().getResources().getColor(colorResId)));
|
||||
}
|
||||
|
||||
static IconAndColor of(@DrawableRes int icon, @ColorRes int color) {
|
||||
return new IconAndColor(icon, color);
|
||||
}
|
||||
|
||||
public int getIconResId() {
|
||||
return iconResId;
|
||||
// TODO: fix duplication
|
||||
|
||||
static IconAndColor forNumberRating(NumberRating rating) {
|
||||
switch (rating) {
|
||||
case NEUTRAL:
|
||||
return of(R.drawable.ic_thumbs_up_down_black_24dp, R.color.rateNeutral);
|
||||
case POSITIVE:
|
||||
return of(R.drawable.ic_thumb_up_black_24dp, R.color.ratePositive);
|
||||
case NEGATIVE:
|
||||
return of(R.drawable.ic_thumb_down_black_24dp, R.color.rateNegative);
|
||||
}
|
||||
return new IconAndColor(R.drawable.ic_thumbs_up_down_black_24dp, R.color.notFound, true);
|
||||
}
|
||||
|
||||
public int getColorResId() {
|
||||
return colorResId;
|
||||
static IconAndColor forNumberRating(NumberInfo.Rating rating) {
|
||||
switch (rating) {
|
||||
case NEUTRAL:
|
||||
return of(R.drawable.ic_thumbs_up_down_black_24dp, R.color.rateNeutral);
|
||||
case POSITIVE:
|
||||
return of(R.drawable.ic_thumb_up_black_24dp, R.color.ratePositive);
|
||||
case NEGATIVE:
|
||||
return of(R.drawable.ic_thumb_down_black_24dp, R.color.rateNegative);
|
||||
}
|
||||
return new IconAndColor(R.drawable.ic_thumbs_up_down_black_24dp, R.color.notFound, true);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,27 +1,42 @@
|
|||
package dummydomain.yetanothercallblocker;
|
||||
|
||||
import android.Manifest;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Intent;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.widget.SwitchCompat;
|
||||
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.widget.SwitchCompat;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import dummydomain.yetanothercallblocker.sia.DatabaseSingleton;
|
||||
import dummydomain.yetanothercallblocker.sia.model.NumberInfo;
|
||||
import dummydomain.yetanothercallblocker.sia.model.database.DbManager;
|
||||
|
||||
public class MainActivity extends AppCompatActivity {
|
||||
|
||||
private CallLogItemRecyclerViewAdapter callLogAdapter;
|
||||
private List<CallLogItem> callLogItems = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_main);
|
||||
|
||||
callLogAdapter = new CallLogItemRecyclerViewAdapter(callLogItems, this::onCallLogItemClicked);
|
||||
RecyclerView recyclerView = findViewById(R.id.callLogList);
|
||||
recyclerView.setAdapter(callLogAdapter);
|
||||
|
||||
SwitchCompat notificationsSwitch = findViewById(R.id.notificationsEnabledSwitch);
|
||||
notificationsSwitch.setChecked(CallReceiver.isEnabled(this));
|
||||
notificationsSwitch.setOnCheckedChangeListener((buttonView, isChecked)
|
||||
|
@ -68,6 +83,15 @@ public class MainActivity extends AppCompatActivity {
|
|||
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||
|
||||
// TODO: handle
|
||||
|
||||
loadCallLog();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStart() {
|
||||
super.onStart();
|
||||
|
||||
loadCallLog();
|
||||
}
|
||||
|
||||
public void onDownloadDbClick(View view) {
|
||||
|
@ -96,6 +120,33 @@ public class MainActivity extends AppCompatActivity {
|
|||
startActivity(new Intent(this, DebugActivity.class));
|
||||
}
|
||||
|
||||
private void onCallLogItemClicked(CallLogItem item) {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(this)
|
||||
.setTitle(item.number);
|
||||
|
||||
@SuppressLint("InflateParams")
|
||||
View view = getLayoutInflater().inflate(R.layout.info_dialog, null);
|
||||
|
||||
TextView featuredNameView = view.findViewById(R.id.featuredName);
|
||||
if (item.numberInfo.name != null) {
|
||||
featuredNameView.setText(item.numberInfo.name);
|
||||
} else {
|
||||
featuredNameView.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
ReviewsSummaryHelper.populateSummary(view.findViewById(R.id.reviews_summary),
|
||||
item.numberInfo.communityDatabaseItem);
|
||||
|
||||
builder.setView(view);
|
||||
|
||||
builder.setNeutralButton(R.string.online_reviews, (d, w)
|
||||
-> ReviewsActivity.startForNumber(this, item.number));
|
||||
|
||||
builder.setNegativeButton(R.string.back, null);
|
||||
|
||||
builder.show();
|
||||
}
|
||||
|
||||
enum UpdateUiState {HIDDEN, NO_DB, DOWNLOADING_DB, ERROR}
|
||||
|
||||
private void updateNoDbUi(UpdateUiState state) {
|
||||
|
@ -107,4 +158,41 @@ public class MainActivity extends AppCompatActivity {
|
|||
findViewById(R.id.dbCouldNotBeDownloaded).setVisibility(state == UpdateUiState.ERROR ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
|
||||
private void loadCallLog() {
|
||||
if (!PermissionHelper.havePermission(this, Manifest.permission.READ_CALL_LOG)) {
|
||||
setCallLogVisibility(false);
|
||||
return;
|
||||
}
|
||||
|
||||
new AsyncTask<Void, Void, List<CallLogItem>>() {
|
||||
@Override
|
||||
protected List<CallLogItem> doInBackground(Void... voids) {
|
||||
List<CallLogItem> items = CallLogHelper.getRecentCalls(MainActivity.this, 10);
|
||||
|
||||
for (CallLogItem item : items) {
|
||||
item.numberInfo = DatabaseSingleton.getCommunityDatabase().isOperational()
|
||||
? DatabaseSingleton.getNumberInfo(item.number)
|
||||
: new NumberInfo();
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(List<CallLogItem> items) {
|
||||
callLogItems.clear();
|
||||
callLogItems.addAll(items);
|
||||
callLogAdapter.notifyDataSetChanged();
|
||||
|
||||
setCallLogVisibility(true);
|
||||
}
|
||||
}.execute();
|
||||
}
|
||||
|
||||
private void setCallLogVisibility(boolean visible) {
|
||||
int visibility = visible ? View.VISIBLE : View.GONE;
|
||||
findViewById(R.id.callLogTitle).setVisibility(visibility);
|
||||
findViewById(R.id.callLogList).setVisibility(visibility);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
package dummydomain.yetanothercallblocker;
|
||||
|
||||
import android.Manifest;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Build;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.core.app.ActivityCompat;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
@ -39,4 +41,9 @@ public class PermissionHelper {
|
|||
}
|
||||
}
|
||||
|
||||
public static boolean havePermission(Context context, String permission) {
|
||||
return ContextCompat.checkSelfPermission(context, permission)
|
||||
== PackageManager.PERMISSION_GRANTED;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
package dummydomain.yetanothercallblocker;
|
||||
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import dummydomain.yetanothercallblocker.sia.model.database.CommunityDatabaseItem;
|
||||
|
||||
public class ReviewsSummaryHelper {
|
||||
|
||||
public static void populateSummary(View reviewsSummary, CommunityDatabaseItem item) {
|
||||
reviewsSummary.setVisibility(View.VISIBLE);
|
||||
|
||||
Map<Integer, Integer> map = new HashMap<>(3);
|
||||
map.put(R.id.summary_text_negative, item != null ? item.getNegativeRatingsCount() : 0);
|
||||
map.put(R.id.summary_text_neutral, item != null ? item.getNeutralRatingsCount() : 0);
|
||||
map.put(R.id.summary_text_positive, item != null ? item.getPositiveRatingsCount() : 0);
|
||||
for (Map.Entry<Integer, Integer> e : map.entrySet()) {
|
||||
((TextView) reviewsSummary.findViewById(e.getKey())).setText(
|
||||
String.valueOf(e.getValue()));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="#00C853"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M9,5v2h6.59L4,18.59 5.41,20 17,8.41V15h2V5z" />
|
||||
</vector>
|
|
@ -0,0 +1,10 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="#C53929"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M19.59,7L12,14.59 6.41,9H11V7H3v8h2v-4.59l7,7 9,-9z" />
|
||||
</vector>
|
|
@ -0,0 +1,10 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="#00A8FF"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M20,5.41L18.59,4 7,15.59V9H5v10h10v-2H8.41z" />
|
||||
</vector>
|
|
@ -1,5 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout 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"
|
||||
|
@ -18,7 +19,7 @@
|
|||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:divider="?android:listDivider"
|
||||
android:orientation="vertical"
|
||||
android:paddingLeft="@dimen/item_padding"
|
||||
|
@ -97,4 +98,26 @@
|
|||
android:layout_marginBottom="@dimen/text_margin"
|
||||
android:text="@string/auto_update_enabled" />
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/callLogTitle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="start"
|
||||
android:layout_marginStart="@dimen/text_margin"
|
||||
android:layout_marginLeft="@dimen/text_margin"
|
||||
android:paddingTop="@dimen/item_padding"
|
||||
android:text="@string/recent_calls"
|
||||
android:textAlignment="textStart" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/callLogList"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginLeft="@dimen/item_padding"
|
||||
android:layout_marginTop="@dimen/item_padding"
|
||||
android:layout_marginRight="@dimen/item_padding"
|
||||
android:layout_marginBottom="@dimen/item_padding"
|
||||
app:layoutManager="LinearLayoutManager"
|
||||
tools:listitem="@layout/call_log_item" />
|
||||
</LinearLayout>
|
|
@ -0,0 +1,57 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:gravity="center_vertical|start"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/callTypeIcon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="1dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginEnd="1dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:src="@drawable/ic_call_missed_24dp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/item_number"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:textAppearance="?attr/textAppearanceListItem"
|
||||
tools:text="+12345678901" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/numberInfoIcon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="6dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginRight="1dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:src="@drawable/ic_thumb_down_black_24dp" />
|
||||
|
||||
<Space
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/time"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/text_margin"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginEnd="@dimen/text_margin"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:textAppearance="?attr/textAppearanceListItemSecondary"
|
||||
android:textSize="12sp"
|
||||
tools:text="1 minute ago" />
|
||||
</LinearLayout>
|
|
@ -0,0 +1,23 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/featuredName"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="20sp"
|
||||
tools:text="Featured company name" />
|
||||
|
||||
<include
|
||||
layout="@layout/reviews_summary"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="6dp" />
|
||||
|
||||
</LinearLayout>
|
|
@ -51,6 +51,10 @@
|
|||
<string name="downloading_db">Downloading DB…</string>
|
||||
<string name="db_could_not_be_downloaded">Database couldn\'t be downloaded</string>
|
||||
|
||||
<string name="recent_calls">Recent calls</string>
|
||||
<string name="online_reviews">Online reviews</string>
|
||||
<string name="back">Back</string>
|
||||
|
||||
<string name="incoming_call_notifications_enabled">Incoming call notifications enabled</string>
|
||||
<string name="block_calls">Block unwanted calls</string>
|
||||
<string name="auto_update_enabled">Auto-update enabled</string>
|
||||
|
|
Loading…
Reference in New Issue