Skip to content

Commit

Permalink
Implement last update time storage
Browse files Browse the repository at this point in the history
  • Loading branch information
gentlecat committed Dec 27, 2024
1 parent 8bdf3b5 commit 46295e5
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 25 deletions.
5 changes: 5 additions & 0 deletions app/src/main/java/me/tsukanov/counter/domain/Counter.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package me.tsukanov.counter.domain;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import me.tsukanov.counter.domain.exception.InvalidNameException;
import me.tsukanov.counter.domain.exception.InvalidValueException;
import org.joda.time.DateTime;

public interface Counter<T> {

Expand All @@ -14,6 +16,9 @@ public interface Counter<T> {
@NonNull
T getValue();

@Nullable
DateTime getLastUpdatedDate();

void setValue(@NonNull T newValue) throws InvalidValueException;

void increment();
Expand Down
32 changes: 32 additions & 0 deletions app/src/main/java/me/tsukanov/counter/domain/IntegerCounter.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@

import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import me.tsukanov.counter.domain.exception.CounterException;
import me.tsukanov.counter.domain.exception.InvalidNameException;
import me.tsukanov.counter.domain.exception.InvalidValueException;
import org.joda.time.DateTime;

/**
* Variation of the {@link Counter} that uses {@link Integer} type as a value. Names (identifiers)
Expand All @@ -20,12 +22,14 @@ public class IntegerCounter implements Counter<Integer> {

private String name;
private Integer value = DEFAULT_VALUE;
private @Nullable DateTime lastUpdate;

public IntegerCounter(@NonNull final String name) throws CounterException {
if (!isValidName(name)) {
throw new InvalidNameException("Provided name is invalid");
}
this.name = name;
this.lastUpdate = new DateTime();
}

public IntegerCounter(@NonNull final String name, @NonNull final Integer value)
Expand All @@ -42,6 +46,27 @@ public IntegerCounter(@NonNull final String name, @NonNull final Integer value)
value, MIN_VALUE, MAX_VALUE));
}
this.value = value;

this.lastUpdate = null;
}

public IntegerCounter(
@NonNull final String name, @NonNull final Integer value, @Nullable final DateTime lastUpdate)
throws CounterException {
if (!isValidName(name)) {
throw new InvalidNameException("Provided name is invalid");
}
this.name = name;

if (!isValidValue(value)) {
throw new InvalidValueException(
String.format(
"Desired value (%s) is outside of allowed range: %s to %s",
value, MIN_VALUE, MAX_VALUE));
}
this.value = value;

this.lastUpdate = lastUpdate;
}

@NonNull
Expand All @@ -61,6 +86,12 @@ public Integer getValue() {
return this.value;
}

@Override
@Nullable
public DateTime getLastUpdatedDate() {
return this.lastUpdate;
}

public void setValue(@NonNull final Integer newValue) throws InvalidValueException {
if (!isValidValue(newValue)) {
throw new InvalidValueException(
Expand All @@ -69,6 +100,7 @@ public void setValue(@NonNull final Integer newValue) throws InvalidValueExcepti
newValue, MIN_VALUE, MAX_VALUE));
}
this.value = newValue;
this.lastUpdate = new DateTime();
}

public void increment() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@
import me.tsukanov.counter.repository.exceptions.MissingCounterException;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVPrinter;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.joda.time.format.DateTimeFormatter;
import org.joda.time.format.ISODateTimeFormat;

/**
* Counter storage that uses {@link SharedPreferences} as a medium.
Expand All @@ -27,9 +31,15 @@
public class SharedPrefsCounterStorage implements CounterStorage<IntegerCounter> {

private static final String TAG = SharedPrefsCounterStorage.class.getSimpleName();
private static final String DATA_FILE_NAME = "counters";

private final SharedPreferences sharedPreferences;
private static final String VALUES_FILE_NAME = "counters";
private static final String UPDATE_TIMESTAMPS_FILE_NAME = "update-timestamps";
private static final DateTimeFormatter TIMESTAMP_FORMATTER =
ISODateTimeFormat.basicDateTimeNoMillis().withZone(DateTimeZone.getDefault());

private final SharedPreferences values;
private final SharedPreferences updateTimestamps;

private final BroadcastHelper broadcastHelper;
private final String defaultCounterName;

Expand All @@ -42,7 +52,9 @@ public SharedPrefsCounterStorage(
@NonNull final Context context,
@NonNull final BroadcastHelper broadcastHelper,
@NonNull final String defaultCounterName) {
this.sharedPreferences = context.getSharedPreferences(DATA_FILE_NAME, Context.MODE_PRIVATE);
this.values = context.getSharedPreferences(VALUES_FILE_NAME, Context.MODE_PRIVATE);
this.updateTimestamps =
context.getSharedPreferences(UPDATE_TIMESTAMPS_FILE_NAME, Context.MODE_PRIVATE);
this.broadcastHelper = broadcastHelper;
this.defaultCounterName = defaultCounterName;
}
Expand All @@ -52,25 +64,32 @@ public SharedPrefsCounterStorage(
public List<IntegerCounter> readAll(boolean addDefault) {
final List<IntegerCounter> counters = new LinkedList<>();

final Map<String, ?> dataMap = sharedPreferences.getAll();
final Map<String, ?> valuesMap = values.getAll();

try {
if (dataMap.isEmpty() && addDefault) {
if (valuesMap.isEmpty() && addDefault) {
final IntegerCounter defaultCounter = new IntegerCounter(this.defaultCounterName);
counters.add(defaultCounter);
write(defaultCounter);
} else {
for (Map.Entry<String, ?> entry : dataMap.entrySet()) {
counters.add(new IntegerCounter(entry.getKey(), (Integer) entry.getValue()));
}
return counters;
}

for (Map.Entry<String, ?> valEntry : valuesMap.entrySet()) {
final String updateTimestampStr = updateTimestamps.getString(valEntry.getKey(), null);
final DateTime updateTimestamp =
updateTimestampStr != null
? DateTime.parse(updateTimestampStr, TIMESTAMP_FORMATTER)
: null;

counters.add(
new IntegerCounter(valEntry.getKey(), (Integer) valEntry.getValue(), updateTimestamp));
}
Collections.sort(counters, (x, y) -> x.getName().compareTo(y.getName()));
return counters;

} catch (CounterException e) {
throw new RuntimeException(e);
}

Collections.sort(counters, (x, y) -> x.getName().compareTo(y.getName()));

return counters;
}

@NonNull
Expand Down Expand Up @@ -101,9 +120,14 @@ public IntegerCounter getFirst() {
@SuppressLint("ApplySharedPref")
@Override
public void write(@NonNull final IntegerCounter counter) {
final SharedPreferences.Editor prefsEditor = sharedPreferences.edit();
prefsEditor.putInt(counter.getName(), counter.getValue());
prefsEditor.commit();
values.edit().putInt(counter.getName(), counter.getValue()).commit();

if (counter.getLastUpdatedDate() != null) {
updateTimestamps
.edit()
.putString(counter.getName(), counter.getLastUpdatedDate().toString(TIMESTAMP_FORMATTER))
.commit();
}

broadcastHelper.sendBroadcast(Actions.COUNTER_SET_CHANGE);
}
Expand All @@ -113,7 +137,7 @@ public void write(@NonNull final IntegerCounter counter) {
public void overwriteAll(@NonNull List<IntegerCounter> counters) {
Log.i(TAG, String.format("Writing %s counters to storage", counters.size()));

final SharedPreferences.Editor prefsEditor = sharedPreferences.edit();
final SharedPreferences.Editor prefsEditor = values.edit();
prefsEditor.clear();
for (IntegerCounter c : counters) {
prefsEditor.putInt(c.getName(), c.getValue());
Expand All @@ -132,7 +156,7 @@ public void overwriteAll(@NonNull List<IntegerCounter> counters) {
@SuppressLint("ApplySharedPref")
@Override
public void delete(@NonNull Object counterName) {
final SharedPreferences.Editor prefsEditor = sharedPreferences.edit();
final SharedPreferences.Editor prefsEditor = values.edit();
prefsEditor.remove(counterName.toString());
prefsEditor.commit();

Expand All @@ -142,7 +166,7 @@ public void delete(@NonNull Object counterName) {
@SuppressLint("ApplySharedPref")
@Override
public void wipe() {
SharedPreferences.Editor prefsEditor = sharedPreferences.edit();
SharedPreferences.Editor prefsEditor = values.edit();
prefsEditor.clear();
prefsEditor.commit();

Expand All @@ -152,14 +176,21 @@ public void wipe() {
@NonNull
@Override
public String toCsv() throws IOException {

final StringBuilder output = new StringBuilder();
final CSVPrinter csvPrinter = new CSVPrinter(output, CSVFormat.DEFAULT);
try (CSVPrinter csvPrinter = new CSVPrinter(output, CSVFormat.DEFAULT)) {

for (final IntegerCounter c : readAll(false)) {
csvPrinter.printRecord(c.getName(), c.getValue());
}
csvPrinter.printRecord("Name", "Value", "Last Update");

for (final IntegerCounter c : readAll(false)) {
csvPrinter.printRecord(
c.getName(),
c.getValue(),
c.getLastUpdatedDate() != null
? c.getLastUpdatedDate().toString(TIMESTAMP_FORMATTER)
: "");
}

return output.toString();
return output.toString();
}
}
}
1 change: 1 addition & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
<string name="app_name">Counter</string>
<string name="plus" translatable="false">+</string>
<string name="minus" translatable="false">-</string>
<string name="last_update_timestamp">Last updated at {timestamp}</string>

<!-- Menu -->
<string name="drawer_open">Open navigation</string>
Expand Down

0 comments on commit 46295e5

Please sign in to comment.