"src/git@transfer.hft-stuttgart.de:cota/cota-backend.git" did not exist on "b8793634e87adca5bb1e8dd2a15470b4c7e5d43e"
Commit 9b3438fb authored by Lückemeyer's avatar Lückemeyer
Browse files

Gemini added WordCount for boxes in memorize combo box

parent 8fb81ab9
...@@ -19,8 +19,6 @@ public interface CardDao { ...@@ -19,8 +19,6 @@ public interface CardDao {
/** /**
* Returns all cards whose most recent try_record for the given direction * Returns all cards whose most recent try_record for the given direction
* places them in the given Leitner box. * places them in the given Leitner box.
* Cards with no try_record for this direction are excluded here —
* use getUnattemptedForDirectionSync for those.
*/ */
@Query("SELECT c.* FROM card c " + @Query("SELECT c.* FROM card c " +
"JOIN ( " + "JOIN ( " +
...@@ -41,9 +39,25 @@ public interface CardDao { ...@@ -41,9 +39,25 @@ public interface CardDao {
"ORDER BY c.volet_id ASC, c.id ASC") "ORDER BY c.volet_id ASC, c.id ASC")
List<Card> getByBoxSync(int box, String direction); List<Card> getByBoxSync(int box, String direction);
@Query("SELECT COUNT(DISTINCT c.id) FROM card c " +
"JOIN ( " +
" SELECT tr.leitner_state_id, ls.card_id, ls.box_number " +
" FROM try_record tr " +
" JOIN leitner_state ls ON ls.id = tr.leitner_state_id " +
" WHERE ls.direction = :direction " +
" AND tr.responded_at = ( " +
" SELECT MAX(tr2.responded_at) " +
" FROM try_record tr2 " +
" JOIN leitner_state ls2 ON ls2.id = tr2.leitner_state_id " +
" WHERE ls2.card_id = ls.card_id " +
" AND ls2.direction = :direction " +
" ) " +
") latest ON latest.card_id = c.id " +
"WHERE latest.box_number = :box")
int countByBoxSync(int box, String direction);
/** /**
* Cards that have never been attempted in the given direction. * Cards that have never been attempted in the given direction.
* These implicitly belong to box 1 for that direction.
*/ */
@Query("SELECT * FROM card c " + @Query("SELECT * FROM card c " +
"WHERE NOT EXISTS ( " + "WHERE NOT EXISTS ( " +
...@@ -53,4 +67,12 @@ public interface CardDao { ...@@ -53,4 +67,12 @@ public interface CardDao {
") " + ") " +
"ORDER BY c.volet_id ASC, c.id ASC") "ORDER BY c.volet_id ASC, c.id ASC")
List<Card> getUnattemptedForDirectionSync(String direction); List<Card> getUnattemptedForDirectionSync(String direction);
@Query("SELECT COUNT(*) FROM card c " +
"WHERE NOT EXISTS ( " +
" SELECT 1 FROM try_record tr " +
" JOIN leitner_state ls ON ls.id = tr.leitner_state_id " +
" WHERE ls.card_id = c.id AND ls.direction = :direction " +
")")
int countUnattemptedForDirectionSync(String direction);
} }
package dev.lueckemeyer.vocoach.ui.memorize; package dev.lueckemeyer.vocoach.ui.memorize;
import android.content.Context;
import android.graphics.Typeface; import android.graphics.Typeface;
import android.os.Bundle; import android.os.Bundle;
import android.view.*; import android.view.*;
...@@ -10,6 +11,7 @@ import java.util.ArrayList; ...@@ -10,6 +11,7 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import dev.lueckemeyer.vocoach.R;
import dev.lueckemeyer.vocoach.databinding.FragmentMemorizeBinding; import dev.lueckemeyer.vocoach.databinding.FragmentMemorizeBinding;
import dev.lueckemeyer.vocoach.db.VocabDatabase; import dev.lueckemeyer.vocoach.db.VocabDatabase;
import dev.lueckemeyer.vocoach.db.dao.VoletWithContext; import dev.lueckemeyer.vocoach.db.dao.VoletWithContext;
...@@ -58,7 +60,7 @@ public class MemorizeFragment extends Fragment { ...@@ -58,7 +60,7 @@ public class MemorizeFragment extends Fragment {
binding.toggleDirection.setChecked(false); // start on French binding.toggleDirection.setChecked(false); // start on French
binding.toggleDirection.setOnCheckedChangeListener((btn, checked) -> { binding.toggleDirection.setOnCheckedChangeListener((btn, checked) -> {
boxDirection = checked ? "native_to_fr" : "fr_to_native"; boxDirection = checked ? "native_to_fr" : "fr_to_native";
if (!byVolet) loadTable(binding.spinnerSelection.getSelectedItemPosition()); if (!byVolet) refreshSpinner();
}); });
// ── Spinner selection triggers table refresh ────────────────────────── // ── Spinner selection triggers table refresh ──────────────────────────
...@@ -95,15 +97,22 @@ public class MemorizeFragment extends Fragment { ...@@ -95,15 +97,22 @@ public class MemorizeFragment extends Fragment {
}); });
}); });
} else { } else {
List<String> boxes = new ArrayList<>(); exec.execute(() -> {
for (int i = 1; i <= 6; i++) boxes.add("Box " + i); List<BoxItem> boxes = new ArrayList<>();
ArrayAdapter<String> adapter = new ArrayAdapter<>( for (int i = 1; i <= 6; i++) {
requireContext(), int count = db.cardDao().countByBoxSync(i, boxDirection);
android.R.layout.simple_spinner_item, boxes); if (i == 1) {
adapter.setDropDownViewResource( count += db.cardDao().countUnattemptedForDirectionSync(boxDirection);
android.R.layout.simple_spinner_dropdown_item); }
binding.spinnerSelection.setAdapter(adapter); boxes.add(new BoxItem("Box " + i, count));
loadTable(0); }
requireActivity().runOnUiThread(() -> {
if (getContext() == null) return;
BoxAdapter adapter = new BoxAdapter(requireContext(), boxes);
binding.spinnerSelection.setAdapter(adapter);
loadTable(0);
});
});
} }
} }
...@@ -186,4 +195,43 @@ public class MemorizeFragment extends Fragment { ...@@ -186,4 +195,43 @@ public class MemorizeFragment extends Fragment {
super.onDestroyView(); super.onDestroyView();
binding = null; binding = null;
} }
// ── Box Spinner Helpers ──────────────────────────────────────────────────
private static class BoxItem {
final String label;
final int count;
BoxItem(String label, int count) { this.label = label; this.count = count; }
@NonNull @Override public String toString() { return label; }
}
private class BoxAdapter extends ArrayAdapter<BoxItem> {
public BoxAdapter(@NonNull Context context, @NonNull List<BoxItem> items) {
super(context, R.layout.item_spinner_with_count, items);
}
@NonNull
@Override
public View getView(int pos, @Nullable View conv, @NonNull ViewGroup parent) {
return createView(pos, conv, parent);
}
@Override
public View getDropDownView(int pos, @Nullable View conv, @NonNull ViewGroup parent) {
return createView(pos, conv, parent);
}
private View createView(int pos, View conv, ViewGroup parent) {
if (conv == null) {
conv = LayoutInflater.from(getContext())
.inflate(R.layout.item_spinner_with_count, parent, false);
}
BoxItem item = getItem(pos);
if (item != null) {
((TextView) conv.findViewById(R.id.text_main)).setText(item.label);
((TextView) conv.findViewById(R.id.text_count)).setText(String.valueOf(item.count));
}
return conv;
}
}
} }
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="48dp"
android:paddingStart="12dp"
android:paddingEnd="12dp">
<TextView
android:id="@+id/text_main"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
android:layout_toStartOf="@+id/text_count"
android:ellipsize="marquee"
android:singleLine="true"
android:textColor="?android:attr/textColorPrimary"
android:textSize="16sp" />
<TextView
android:id="@+id/text_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:paddingStart="8dp"
android:textColor="?android:attr/textColorSecondary"
android:textSize="14sp" />
</RelativeLayout>
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment