Før kameratilgang

This commit is contained in:
ErolHaagenrud 2025-12-11 10:18:19 +01:00
parent 30053eb060
commit 4e67902021
5 changed files with 140 additions and 73 deletions

View file

@ -4,6 +4,14 @@
<selectionStates> <selectionStates>
<SelectionState runConfigName="app"> <SelectionState runConfigName="app">
<option name="selectionMode" value="DROPDOWN" /> <option name="selectionMode" value="DROPDOWN" />
<DropdownSelection timestamp="2025-12-11T08:50:24.083106200Z">
<Target type="DEFAULT_BOOT">
<handle>
<DeviceId pluginId="LocalEmulator" identifier="path=C:\Users\ErolHaagenrud\.android\avd\Pixel_7_Pro.avd" />
</handle>
</Target>
</DropdownSelection>
<DialogSelection />
</SelectionState> </SelectionState>
</selectionStates> </selectionStates>
</component> </component>

View file

@ -39,6 +39,17 @@
<category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter> </intent-filter>
</activity> </activity>
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="com.kbs.kbsintranett.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
</application> </application>
</manifest> </manifest>

View file

@ -40,6 +40,7 @@ import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import org.json.JSONArray; import org.json.JSONArray;
import org.json.JSONException; import org.json.JSONException;
@ -105,12 +106,10 @@ public class FormsFragment extends Fragment {
private Map<String, View> childInputViews = new HashMap<>(); private Map<String, View> childInputViews = new HashMap<>();
private Map<String, Boolean> childRequiredFieldsMap = new HashMap<>(); private Map<String, Boolean> childRequiredFieldsMap = new HashMap<>();
private Map<String, Uri> childFileUploads = new HashMap<>(); private Map<String, Uri> childFileUploads = new HashMap<>();
// Lagring av Nested Entries // Lagring av Nested Entries
private List<NestedEntry> nestedEntries = new ArrayList<>(); private List<NestedEntry> nestedEntries = new ArrayList<>();
private LinearLayout nestedEntriesContainer; private LinearLayout nestedEntriesContainer;
private TextView totalAmountView; private TextView totalAmountView;
private String pendingFileFieldId = null; private String pendingFileFieldId = null;
private boolean isSelectingForChild = false; private boolean isSelectingForChild = false;
private ActivityResultLauncher<Intent> filePickerLauncher; private ActivityResultLauncher<Intent> filePickerLauncher;
@ -123,7 +122,6 @@ public class FormsFragment extends Fragment {
@Override @Override
public void onCreate(@Nullable Bundle savedInstanceState) { public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
filePickerLauncher = registerForActivityResult( filePickerLauncher = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(), new ActivityResultContracts.StartActivityForResult(),
result -> { result -> {
@ -354,7 +352,6 @@ public class FormsFragment extends Fragment {
private void openChildFormDialog(int childFormId) { private void openChildFormDialog(int childFormId) {
if (getActivity() == null) return; if (getActivity() == null) return;
ProgressBar pBar = new ProgressBar(getContext()); ProgressBar pBar = new ProgressBar(getContext());
AlertDialog loadingDialog = new AlertDialog.Builder(getContext()) AlertDialog loadingDialog = new AlertDialog.Builder(getContext())
.setView(pBar) .setView(pBar)
@ -383,7 +380,7 @@ public class FormsFragment extends Fragment {
private void showChildFormDialog(GravityForm childForm) { private void showChildFormDialog(GravityForm childForm) {
AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
builder.setTitle(childForm.title); // FJERNET: builder.setTitle(childForm.title); - Brukeren ønsket ikke tittel i popup
childInputViews.clear(); childInputViews.clear();
childRequiredFieldsMap.clear(); childRequiredFieldsMap.clear();
@ -427,7 +424,6 @@ public class FormsFragment extends Fragment {
builder.setView(scrollView); builder.setView(scrollView);
builder.setPositiveButton("Legg til vedlegg", null); builder.setPositiveButton("Legg til vedlegg", null);
builder.setNegativeButton("Avbryt", (d, w) -> d.dismiss()); builder.setNegativeButton("Avbryt", (d, w) -> d.dismiss());
AlertDialog dialog = builder.create(); AlertDialog dialog = builder.create();
dialog.show(); dialog.show();
@ -438,7 +434,6 @@ public class FormsFragment extends Fragment {
private void submitChildForm(int childFormId, AlertDialog dialog) { private void submitChildForm(int childFormId, AlertDialog dialog) {
JSONObject inputValues = new JSONObject(); JSONObject inputValues = new JSONObject();
for (Map.Entry<String, View> entry : childInputViews.entrySet()) { for (Map.Entry<String, View> entry : childInputViews.entrySet()) {
String val = getInputValueGeneric(entry.getValue()); String val = getInputValueGeneric(entry.getValue());
if (!val.isEmpty()) { if (!val.isEmpty()) {
@ -474,17 +469,26 @@ public class FormsFragment extends Fragment {
RetrofitClient.getApiService().submitMultipartForm(childFormId, textParts, fileParts).enqueue(new retrofit2.Callback<JsonElement>() { RetrofitClient.getApiService().submitMultipartForm(childFormId, textParts, fileParts).enqueue(new retrofit2.Callback<JsonElement>() {
@Override @Override
public void onResponse(retrofit2.Call<JsonElement> call, retrofit2.Response<JsonElement> response) { public void onResponse(retrofit2.Call<JsonElement> call, retrofit2.Response<JsonElement> response) {
if (response.isSuccessful()) { if (response.isSuccessful() && response.body() != null) {
try { try {
JSONObject json = new JSONObject(response.body().toString()); JsonObject json = response.body().getAsJsonObject();
if (json.optBoolean("is_valid")) { if (json.has("is_valid") && json.get("is_valid").getAsBoolean()) {
String entryId = json.getString("entry_id"); String entryId = json.has("entry_id") ? json.get("entry_id").getAsString() : "";
// NB: Tilpass ID-ene her hvis skjema 18 endres.
// ID 3 = Beskrivelse, ID 4 = Beløp
String desc = getInputValueGeneric(childInputViews.get("3")); String desc = getInputValueGeneric(childInputViews.get("3"));
String price = getInputValueGeneric(childInputViews.get("4")); String price = getInputValueGeneric(childInputViews.get("4"));
addNestedEntry(entryId, desc, price); addNestedEntry(entryId, desc, price);
dialog.dismiss(); dialog.dismiss();
} else {
Toast.makeText(getContext(), "Ugyldig respons fra server", Toast.LENGTH_SHORT).show();
}
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(getContext(), "Feil ved parsing av svar", Toast.LENGTH_SHORT).show();
} }
} catch (JSONException e) { e.printStackTrace(); }
} else { } else {
Toast.makeText(getContext(), "Feil ved opplasting", Toast.LENGTH_SHORT).show(); Toast.makeText(getContext(), "Feil ved opplasting", Toast.LENGTH_SHORT).show();
} }
@ -494,7 +498,6 @@ public class FormsFragment extends Fragment {
Toast.makeText(getContext(), "Nettverksfeil", Toast.LENGTH_SHORT).show(); Toast.makeText(getContext(), "Nettverksfeil", Toast.LENGTH_SHORT).show();
} }
}); });
} catch (Exception e) { e.printStackTrace(); } } catch (Exception e) { e.printStackTrace(); }
} }
} }
@ -510,10 +513,8 @@ public class FormsFragment extends Fragment {
double total = 0; double total = 0;
List<String> ids = new ArrayList<>(); List<String> ids = new ArrayList<>();
for (NestedEntry entry : nestedEntries) { for (NestedEntry entry : nestedEntries) {
ids.add(entry.id); ids.add(entry.id);
String cleanPrice = entry.price.replaceAll("[^0-9,.]", "").replace(",", "."); String cleanPrice = entry.price.replaceAll("[^0-9,.]", "").replace(",", ".");
try { try {
if (!cleanPrice.isEmpty()) total += Double.parseDouble(cleanPrice); if (!cleanPrice.isEmpty()) total += Double.parseDouble(cleanPrice);
@ -563,7 +564,6 @@ public class FormsFragment extends Fragment {
Toast.makeText(getContext(), "Kunne ikke åpne filvelger", Toast.LENGTH_SHORT).show(); Toast.makeText(getContext(), "Kunne ikke åpne filvelger", Toast.LENGTH_SHORT).show();
} }
}); });
TextView txtFileName = new TextView(getContext()); TextView txtFileName = new TextView(getContext());
txtFileName.setText("Ingen fil valgt"); txtFileName.setText("Ingen fil valgt");
txtFileName.setPadding(20, 0, 0, 0); txtFileName.setPadding(20, 0, 0, 0);
@ -671,7 +671,6 @@ public class FormsFragment extends Fragment {
public void onTextChanged(CharSequence s, int start, int before, int count) {} public void onTextChanged(CharSequence s, int start, int before, int count) {}
public void afterTextChanged(Editable s) { evaluateAllConditionalLogic(); } public void afterTextChanged(Editable s) { evaluateAllConditionalLogic(); }
}); });
container.addView(input); container.addView(input);
views.put(field.id, input); views.put(field.id, input);
req.put(field.id, field.isRequired); req.put(field.id, field.isRequired);
@ -723,6 +722,10 @@ public class FormsFragment extends Fragment {
String cbText = (field.checkboxLabel != null && !field.checkboxLabel.isEmpty()) ? field.checkboxLabel : field.label; String cbText = (field.checkboxLabel != null && !field.checkboxLabel.isEmpty()) ? field.checkboxLabel : field.label;
checkBox.setText(cbText); checkBox.setText(cbText);
String inputId = (field.inputs != null && !field.inputs.isEmpty()) ? field.inputs.get(0).id : field.id; String inputId = (field.inputs != null && !field.inputs.isEmpty()) ? field.inputs.get(0).id : field.id;
// For Consent fields, Gravity Forms typically expects "1" if checked.
checkBox.setTag("1");
checkBox.setOnCheckedChangeListener((b, c) -> evaluateAllConditionalLogic()); checkBox.setOnCheckedChangeListener((b, c) -> evaluateAllConditionalLogic());
container.addView(checkBox); container.addView(checkBox);
views.put(inputId, checkBox); views.put(inputId, checkBox);
@ -731,9 +734,21 @@ public class FormsFragment extends Fragment {
private void renderCheckboxField(LinearLayout container, GravityField field, Map<String, View> views, Map<String, Boolean> req) { private void renderCheckboxField(LinearLayout container, GravityField field, Map<String, View> views, Map<String, Boolean> req) {
if (field.inputs != null) { if (field.inputs != null) {
for (GravityField inputDef : field.inputs) { for (int i = 0; i < field.inputs.size(); i++) {
GravityField inputDef = field.inputs.get(i);
CheckBox checkBox = new CheckBox(getContext()); CheckBox checkBox = new CheckBox(getContext());
checkBox.setText(inputDef.label); checkBox.setText(inputDef.label);
// --- VIKTIG ENDRING: HENT KORREKT VERDI ---
// Gravity Forms sjekkbokser trenger verdien fra "choices" listen, ikke bare "1".
// F.eks: "Ja" hvis valget er "Ja".
String value = "1"; // Fallback
if (field.choices != null && i < field.choices.size()) {
value = field.choices.get(i).value;
}
checkBox.setTag(value);
// -------------------------------------------
checkBox.setOnCheckedChangeListener((b, c) -> evaluateAllConditionalLogic()); checkBox.setOnCheckedChangeListener((b, c) -> evaluateAllConditionalLogic());
container.addView(checkBox); container.addView(checkBox);
views.put(inputDef.id, checkBox); views.put(inputDef.id, checkBox);
@ -744,7 +759,6 @@ public class FormsFragment extends Fragment {
private void renderDateField(LinearLayout container, GravityField field, Map<String, View> views, Map<String, Boolean> req) { private void renderDateField(LinearLayout container, GravityField field, Map<String, View> views, Map<String, Boolean> req) {
EditText dateInput = new EditText(getContext()); EditText dateInput = new EditText(getContext());
// --- DATO LØSNING (Fix for Read Only / Dagens Dato) --- // --- DATO LØSNING (Fix for Read Only / Dagens Dato) ---
if (field.readOnly || (formId == ID_REFUSJON_UTLEGG && "28".equals(field.id))) { if (field.readOnly || (formId == ID_REFUSJON_UTLEGG && "28".equals(field.id))) {
// Sett dagens dato // Sett dagens dato
@ -789,7 +803,6 @@ public class FormsFragment extends Fragment {
for (GravityField subField : inputs) { for (GravityField subField : inputs) {
if (subField.isHidden || "hidden".equals(subField.visibility)) continue; if (subField.isHidden || "hidden".equals(subField.visibility)) continue;
TextView subLabel = new TextView(getContext()); TextView subLabel = new TextView(getContext());
String subLabelText = subField.label; String subLabelText = subField.label;
boolean isSubRequired = parentField.isRequired; boolean isSubRequired = parentField.isRequired;
@ -808,7 +821,6 @@ public class FormsFragment extends Fragment {
subInput.setPadding(30, 30, 30, 30); subInput.setPadding(30, 30, 30, 30);
subInput.setBackgroundResource(android.R.drawable.edit_text); subInput.setBackgroundResource(android.R.drawable.edit_text);
subInput.setInputType(InputType.TYPE_CLASS_TEXT); subInput.setInputType(InputType.TYPE_CLASS_TEXT);
if (isPersonalia && parentField.label.toLowerCase().contains("navn") && !parentField.label.toLowerCase().contains("pårørende")) { if (isPersonalia && parentField.label.toLowerCase().contains("navn") && !parentField.label.toLowerCase().contains("pårørende")) {
String lowerSub = subField.label.toLowerCase(); String lowerSub = subField.label.toLowerCase();
if (lowerSub.contains("fornavn")) subInput.setText(user.getFirstName()); if (lowerSub.contains("fornavn")) subInput.setText(user.getFirstName());
@ -829,7 +841,6 @@ public class FormsFragment extends Fragment {
sectionHeader.setTextColor(Color.parseColor("#0069B3")); sectionHeader.setTextColor(Color.parseColor("#0069B3"));
sectionHeader.setPadding(0, 20, 0, 5); sectionHeader.setPadding(0, 20, 0, 5);
container.addView(sectionHeader); container.addView(sectionHeader);
if (descText != null && !descText.isEmpty()) { if (descText != null && !descText.isEmpty()) {
TextView desc = new TextView(getContext()); TextView desc = new TextView(getContext());
desc.setText(Html.fromHtml(descText, Html.FROM_HTML_MODE_COMPACT)); desc.setText(Html.fromHtml(descText, Html.FROM_HTML_MODE_COMPACT));
@ -858,7 +869,6 @@ public class FormsFragment extends Fragment {
private void evaluateAllConditionalLogic() { private void evaluateAllConditionalLogic() {
if (currentForm == null || currentForm.fields == null) return; if (currentForm == null || currentForm.fields == null) return;
for (GravityField field : currentForm.fields) { for (GravityField field : currentForm.fields) {
if (field.conditionalLogic == null) { if (field.conditionalLogic == null) {
setViewVisibility(field.id, true); setViewVisibility(field.id, true);
@ -874,7 +884,6 @@ public class FormsFragment extends Fragment {
private boolean evaluateLogic(GravityField.ConditionalLogic logic) { private boolean evaluateLogic(GravityField.ConditionalLogic logic) {
if (logic.rules == null || logic.rules.isEmpty()) return true; if (logic.rules == null || logic.rules.isEmpty()) return true;
boolean isAll = "all".equalsIgnoreCase(logic.logicType); boolean isAll = "all".equalsIgnoreCase(logic.logicType);
boolean aggregatedResult = isAll; boolean aggregatedResult = isAll;
@ -927,7 +936,16 @@ public class FormsFragment extends Fragment {
Object item = ((Spinner) view).getSelectedItem(); Object item = ((Spinner) view).getSelectedItem();
return item != null ? item.toString() : ""; return item != null ? item.toString() : "";
} }
if (view instanceof CheckBox) return ((CheckBox) view).isChecked() ? "1" : ""; // --- VIKTIG ENDRING: HENT TAG-VERDI ---
if (view instanceof CheckBox) {
CheckBox cb = (CheckBox) view;
if (cb.isChecked()) {
// Returner verdien lagret i Tag (f.eks "Ja") i stedet for hardkodet "1"
return cb.getTag() != null ? cb.getTag().toString() : "1";
}
return "";
}
// ----------------------------------------
return ""; return "";
} }
@ -991,7 +1009,6 @@ public class FormsFragment extends Fragment {
updateStatus("Sender inn..."); updateStatus("Sender inn...");
String cookie = UserManager.getInstance().getCookie(); String cookie = UserManager.getInstance().getCookie();
Log.d(TAG, "Preparing submission payload: " + inputValues.toString()); Log.d(TAG, "Preparing submission payload: " + inputValues.toString());
if (!fileUploads.isEmpty()) { if (!fileUploads.isEmpty()) {
@ -1018,10 +1035,10 @@ public class FormsFragment extends Fragment {
}); });
} else { } else {
try { try {
String errBody = response.body().string(); // --- BEDRE LOGGING FOR 400 FEIL ---
String errBody = response.body() != null ? response.body().string() : "No body";
Log.e(TAG, "Server error body: " + errBody); Log.e(TAG, "Server error body: " + errBody);
// Prøv å vise feilmeldingen fra serveren updateStatus("Feil (" + response.code() + "): " + errBody); // Viser feilmeldingen i UI
updateStatus("Feil (" + response.code() + "): Sjekk logg.");
} catch(Exception e){} } catch(Exception e){}
} }
} }
@ -1108,7 +1125,6 @@ public class FormsFragment extends Fragment {
int userId = user.getUserId(); int userId = user.getUserId();
if (cookie == null) return; if (cookie == null) return;
String searchJson = "{\"field_filters\":[{\"key\":\"created_by\",\"value\":\"" + userId + "\"}]}"; String searchJson = "{\"field_filters\":[{\"key\":\"created_by\",\"value\":\"" + userId + "\"}]}";
String encodedSearch = ""; String encodedSearch = "";
try { try {
@ -1116,7 +1132,6 @@ public class FormsFragment extends Fragment {
} catch (UnsupportedEncodingException e) { e.printStackTrace(); } } catch (UnsupportedEncodingException e) { e.printStackTrace(); }
String url = BASE_URL_GF + "/entries?form_ids=" + formId + "&search=" + encodedSearch; String url = BASE_URL_GF + "/entries?form_ids=" + formId + "&search=" + encodedSearch;
Request request = new Request.Builder().url(url).header("Cookie", cookie).build(); Request request = new Request.Builder().url(url).header("Cookie", cookie).build();
client.newCall(request).enqueue(new okhttp3.Callback() { client.newCall(request).enqueue(new okhttp3.Callback() {
@ -1170,7 +1185,6 @@ public class FormsFragment extends Fragment {
item.setText("Innsendt: " + date); item.setText("Innsendt: " + date);
item.setPadding(10, 20, 10, 20); item.setPadding(10, 20, 10, 20);
item.setBackgroundResource(android.R.drawable.list_selector_background); item.setBackgroundResource(android.R.drawable.list_selector_background);
View line = new View(getContext()); View line = new View(getContext());
line.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 1)); line.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 1));
line.setBackgroundColor(Color.LTGRAY); line.setBackgroundColor(Color.LTGRAY);
@ -1183,7 +1197,6 @@ public class FormsFragment extends Fragment {
private void prefillFormFromHistory(JSONObject latestEntry) { private void prefillFormFromHistory(JSONObject latestEntry) {
if (latestEntry == null) return; if (latestEntry == null) return;
for (Map.Entry<String, View> entry : inputViews.entrySet()) { for (Map.Entry<String, View> entry : inputViews.entrySet()) {
String fieldId = entry.getKey(); String fieldId = entry.getKey();
View view = entry.getValue(); View view = entry.getValue();
@ -1219,9 +1232,20 @@ public class FormsFragment extends Fragment {
private void clearInputs() { private void clearInputs() {
for (View view : inputViews.values()) { for (View view : inputViews.values()) {
if (view instanceof EditText) ((EditText) view).setText(""); if (view instanceof EditText) {
if (view instanceof CheckBox) ((CheckBox) view).setChecked(false); ((EditText) view).setText("");
if (view instanceof Button) ((TextView) view.getTag()).setText("Ingen fil valgt"); } else if (view instanceof CheckBox) {
((CheckBox) view).setChecked(false);
} else if (view instanceof RadioGroup) {
((RadioGroup) view).clearCheck();
} else if (view instanceof Button) {
// Fix: CheckBox inherits from Button, so we must be careful.
// Only cast to TextView if the tag is actually a TextView (File Upload logic)
Object tag = view.getTag();
if (tag instanceof TextView) {
((TextView) tag).setText("Ingen fil valgt");
}
}
} }
fileUploads.clear(); fileUploads.clear();
nestedEntries.clear(); nestedEntries.clear();

View file

@ -1,5 +1,5 @@
[versions] [versions]
agp = "8.13.1" agp = "8.13.2"
junit = "4.13.2" junit = "4.13.2"
junitVersion = "1.1.5" junitVersion = "1.1.5"
espressoCore = "3.5.1" espressoCore = "3.5.1"

View file

@ -477,6 +477,7 @@ import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import org.json.JSONArray; import org.json.JSONArray;
import org.json.JSONException; import org.json.JSONException;
@ -542,12 +543,10 @@ public class FormsFragment extends Fragment {
private Map<String, View> childInputViews = new HashMap<>(); private Map<String, View> childInputViews = new HashMap<>();
private Map<String, Boolean> childRequiredFieldsMap = new HashMap<>(); private Map<String, Boolean> childRequiredFieldsMap = new HashMap<>();
private Map<String, Uri> childFileUploads = new HashMap<>(); private Map<String, Uri> childFileUploads = new HashMap<>();
// Lagring av Nested Entries // Lagring av Nested Entries
private List<NestedEntry> nestedEntries = new ArrayList<>(); private List<NestedEntry> nestedEntries = new ArrayList<>();
private LinearLayout nestedEntriesContainer; private LinearLayout nestedEntriesContainer;
private TextView totalAmountView; private TextView totalAmountView;
private String pendingFileFieldId = null; private String pendingFileFieldId = null;
private boolean isSelectingForChild = false; private boolean isSelectingForChild = false;
private ActivityResultLauncher<Intent> filePickerLauncher; private ActivityResultLauncher<Intent> filePickerLauncher;
@ -560,7 +559,6 @@ public class FormsFragment extends Fragment {
@Override @Override
public void onCreate(@Nullable Bundle savedInstanceState) { public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
filePickerLauncher = registerForActivityResult( filePickerLauncher = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(), new ActivityResultContracts.StartActivityForResult(),
result -> { result -> {
@ -791,7 +789,6 @@ public class FormsFragment extends Fragment {
private void openChildFormDialog(int childFormId) { private void openChildFormDialog(int childFormId) {
if (getActivity() == null) return; if (getActivity() == null) return;
ProgressBar pBar = new ProgressBar(getContext()); ProgressBar pBar = new ProgressBar(getContext());
AlertDialog loadingDialog = new AlertDialog.Builder(getContext()) AlertDialog loadingDialog = new AlertDialog.Builder(getContext())
.setView(pBar) .setView(pBar)
@ -820,7 +817,7 @@ public class FormsFragment extends Fragment {
private void showChildFormDialog(GravityForm childForm) { private void showChildFormDialog(GravityForm childForm) {
AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
builder.setTitle(childForm.title); // FJERNET: builder.setTitle(childForm.title); - Brukeren ønsket ikke tittel i popup
childInputViews.clear(); childInputViews.clear();
childRequiredFieldsMap.clear(); childRequiredFieldsMap.clear();
@ -864,7 +861,6 @@ public class FormsFragment extends Fragment {
builder.setView(scrollView); builder.setView(scrollView);
builder.setPositiveButton("Legg til vedlegg", null); builder.setPositiveButton("Legg til vedlegg", null);
builder.setNegativeButton("Avbryt", (d, w) -> d.dismiss()); builder.setNegativeButton("Avbryt", (d, w) -> d.dismiss());
AlertDialog dialog = builder.create(); AlertDialog dialog = builder.create();
dialog.show(); dialog.show();
@ -875,7 +871,6 @@ public class FormsFragment extends Fragment {
private void submitChildForm(int childFormId, AlertDialog dialog) { private void submitChildForm(int childFormId, AlertDialog dialog) {
JSONObject inputValues = new JSONObject(); JSONObject inputValues = new JSONObject();
for (Map.Entry<String, View> entry : childInputViews.entrySet()) { for (Map.Entry<String, View> entry : childInputViews.entrySet()) {
String val = getInputValueGeneric(entry.getValue()); String val = getInputValueGeneric(entry.getValue());
if (!val.isEmpty()) { if (!val.isEmpty()) {
@ -911,17 +906,26 @@ public class FormsFragment extends Fragment {
RetrofitClient.getApiService().submitMultipartForm(childFormId, textParts, fileParts).enqueue(new retrofit2.Callback<JsonElement>() { RetrofitClient.getApiService().submitMultipartForm(childFormId, textParts, fileParts).enqueue(new retrofit2.Callback<JsonElement>() {
@Override @Override
public void onResponse(retrofit2.Call<JsonElement> call, retrofit2.Response<JsonElement> response) { public void onResponse(retrofit2.Call<JsonElement> call, retrofit2.Response<JsonElement> response) {
if (response.isSuccessful()) { if (response.isSuccessful() && response.body() != null) {
try { try {
JSONObject json = new JSONObject(response.body().toString()); JsonObject json = response.body().getAsJsonObject();
if (json.optBoolean("is_valid")) { if (json.has("is_valid") && json.get("is_valid").getAsBoolean()) {
String entryId = json.getString("entry_id"); String entryId = json.has("entry_id") ? json.get("entry_id").getAsString() : "";
// NB: Tilpass ID-ene her hvis skjema 18 endres.
// ID 3 = Beskrivelse, ID 4 = Beløp
String desc = getInputValueGeneric(childInputViews.get("3")); String desc = getInputValueGeneric(childInputViews.get("3"));
String price = getInputValueGeneric(childInputViews.get("4")); String price = getInputValueGeneric(childInputViews.get("4"));
addNestedEntry(entryId, desc, price); addNestedEntry(entryId, desc, price);
dialog.dismiss(); dialog.dismiss();
} else {
Toast.makeText(getContext(), "Ugyldig respons fra server", Toast.LENGTH_SHORT).show();
}
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(getContext(), "Feil ved parsing av svar", Toast.LENGTH_SHORT).show();
} }
} catch (JSONException e) { e.printStackTrace(); }
} else { } else {
Toast.makeText(getContext(), "Feil ved opplasting", Toast.LENGTH_SHORT).show(); Toast.makeText(getContext(), "Feil ved opplasting", Toast.LENGTH_SHORT).show();
} }
@ -931,7 +935,6 @@ public class FormsFragment extends Fragment {
Toast.makeText(getContext(), "Nettverksfeil", Toast.LENGTH_SHORT).show(); Toast.makeText(getContext(), "Nettverksfeil", Toast.LENGTH_SHORT).show();
} }
}); });
} catch (Exception e) { e.printStackTrace(); } } catch (Exception e) { e.printStackTrace(); }
} }
} }
@ -947,10 +950,8 @@ public class FormsFragment extends Fragment {
double total = 0; double total = 0;
List<String> ids = new ArrayList<>(); List<String> ids = new ArrayList<>();
for (NestedEntry entry : nestedEntries) { for (NestedEntry entry : nestedEntries) {
ids.add(entry.id); ids.add(entry.id);
String cleanPrice = entry.price.replaceAll("[^0-9,.]", "").replace(",", "."); String cleanPrice = entry.price.replaceAll("[^0-9,.]", "").replace(",", ".");
try { try {
if (!cleanPrice.isEmpty()) total += Double.parseDouble(cleanPrice); if (!cleanPrice.isEmpty()) total += Double.parseDouble(cleanPrice);
@ -1000,7 +1001,6 @@ public class FormsFragment extends Fragment {
Toast.makeText(getContext(), "Kunne ikke åpne filvelger", Toast.LENGTH_SHORT).show(); Toast.makeText(getContext(), "Kunne ikke åpne filvelger", Toast.LENGTH_SHORT).show();
} }
}); });
TextView txtFileName = new TextView(getContext()); TextView txtFileName = new TextView(getContext());
txtFileName.setText("Ingen fil valgt"); txtFileName.setText("Ingen fil valgt");
txtFileName.setPadding(20, 0, 0, 0); txtFileName.setPadding(20, 0, 0, 0);
@ -1108,7 +1108,6 @@ public class FormsFragment extends Fragment {
public void onTextChanged(CharSequence s, int start, int before, int count) {} public void onTextChanged(CharSequence s, int start, int before, int count) {}
public void afterTextChanged(Editable s) { evaluateAllConditionalLogic(); } public void afterTextChanged(Editable s) { evaluateAllConditionalLogic(); }
}); });
container.addView(input); container.addView(input);
views.put(field.id, input); views.put(field.id, input);
req.put(field.id, field.isRequired); req.put(field.id, field.isRequired);
@ -1160,6 +1159,10 @@ public class FormsFragment extends Fragment {
String cbText = (field.checkboxLabel != null && !field.checkboxLabel.isEmpty()) ? field.checkboxLabel : field.label; String cbText = (field.checkboxLabel != null && !field.checkboxLabel.isEmpty()) ? field.checkboxLabel : field.label;
checkBox.setText(cbText); checkBox.setText(cbText);
String inputId = (field.inputs != null && !field.inputs.isEmpty()) ? field.inputs.get(0).id : field.id; String inputId = (field.inputs != null && !field.inputs.isEmpty()) ? field.inputs.get(0).id : field.id;
// For Consent fields, Gravity Forms typically expects "1" if checked.
checkBox.setTag("1");
checkBox.setOnCheckedChangeListener((b, c) -> evaluateAllConditionalLogic()); checkBox.setOnCheckedChangeListener((b, c) -> evaluateAllConditionalLogic());
container.addView(checkBox); container.addView(checkBox);
views.put(inputId, checkBox); views.put(inputId, checkBox);
@ -1168,9 +1171,21 @@ public class FormsFragment extends Fragment {
private void renderCheckboxField(LinearLayout container, GravityField field, Map<String, View> views, Map<String, Boolean> req) { private void renderCheckboxField(LinearLayout container, GravityField field, Map<String, View> views, Map<String, Boolean> req) {
if (field.inputs != null) { if (field.inputs != null) {
for (GravityField inputDef : field.inputs) { for (int i = 0; i < field.inputs.size(); i++) {
GravityField inputDef = field.inputs.get(i);
CheckBox checkBox = new CheckBox(getContext()); CheckBox checkBox = new CheckBox(getContext());
checkBox.setText(inputDef.label); checkBox.setText(inputDef.label);
// --- VIKTIG ENDRING: HENT KORREKT VERDI ---
// Gravity Forms sjekkbokser trenger verdien fra "choices" listen, ikke bare "1".
// F.eks: "Ja" hvis valget er "Ja".
String value = "1"; // Fallback
if (field.choices != null && i < field.choices.size()) {
value = field.choices.get(i).value;
}
checkBox.setTag(value);
// -------------------------------------------
checkBox.setOnCheckedChangeListener((b, c) -> evaluateAllConditionalLogic()); checkBox.setOnCheckedChangeListener((b, c) -> evaluateAllConditionalLogic());
container.addView(checkBox); container.addView(checkBox);
views.put(inputDef.id, checkBox); views.put(inputDef.id, checkBox);
@ -1181,7 +1196,6 @@ public class FormsFragment extends Fragment {
private void renderDateField(LinearLayout container, GravityField field, Map<String, View> views, Map<String, Boolean> req) { private void renderDateField(LinearLayout container, GravityField field, Map<String, View> views, Map<String, Boolean> req) {
EditText dateInput = new EditText(getContext()); EditText dateInput = new EditText(getContext());
// --- DATO LØSNING (Fix for Read Only / Dagens Dato) --- // --- DATO LØSNING (Fix for Read Only / Dagens Dato) ---
if (field.readOnly || (formId == ID_REFUSJON_UTLEGG && "28".equals(field.id))) { if (field.readOnly || (formId == ID_REFUSJON_UTLEGG && "28".equals(field.id))) {
// Sett dagens dato // Sett dagens dato
@ -1226,7 +1240,6 @@ public class FormsFragment extends Fragment {
for (GravityField subField : inputs) { for (GravityField subField : inputs) {
if (subField.isHidden || "hidden".equals(subField.visibility)) continue; if (subField.isHidden || "hidden".equals(subField.visibility)) continue;
TextView subLabel = new TextView(getContext()); TextView subLabel = new TextView(getContext());
String subLabelText = subField.label; String subLabelText = subField.label;
boolean isSubRequired = parentField.isRequired; boolean isSubRequired = parentField.isRequired;
@ -1245,7 +1258,6 @@ public class FormsFragment extends Fragment {
subInput.setPadding(30, 30, 30, 30); subInput.setPadding(30, 30, 30, 30);
subInput.setBackgroundResource(android.R.drawable.edit_text); subInput.setBackgroundResource(android.R.drawable.edit_text);
subInput.setInputType(InputType.TYPE_CLASS_TEXT); subInput.setInputType(InputType.TYPE_CLASS_TEXT);
if (isPersonalia && parentField.label.toLowerCase().contains("navn") && !parentField.label.toLowerCase().contains("pårørende")) { if (isPersonalia && parentField.label.toLowerCase().contains("navn") && !parentField.label.toLowerCase().contains("pårørende")) {
String lowerSub = subField.label.toLowerCase(); String lowerSub = subField.label.toLowerCase();
if (lowerSub.contains("fornavn")) subInput.setText(user.getFirstName()); if (lowerSub.contains("fornavn")) subInput.setText(user.getFirstName());
@ -1266,7 +1278,6 @@ public class FormsFragment extends Fragment {
sectionHeader.setTextColor(Color.parseColor("#0069B3")); sectionHeader.setTextColor(Color.parseColor("#0069B3"));
sectionHeader.setPadding(0, 20, 0, 5); sectionHeader.setPadding(0, 20, 0, 5);
container.addView(sectionHeader); container.addView(sectionHeader);
if (descText != null && !descText.isEmpty()) { if (descText != null && !descText.isEmpty()) {
TextView desc = new TextView(getContext()); TextView desc = new TextView(getContext());
desc.setText(Html.fromHtml(descText, Html.FROM_HTML_MODE_COMPACT)); desc.setText(Html.fromHtml(descText, Html.FROM_HTML_MODE_COMPACT));
@ -1295,7 +1306,6 @@ public class FormsFragment extends Fragment {
private void evaluateAllConditionalLogic() { private void evaluateAllConditionalLogic() {
if (currentForm == null || currentForm.fields == null) return; if (currentForm == null || currentForm.fields == null) return;
for (GravityField field : currentForm.fields) { for (GravityField field : currentForm.fields) {
if (field.conditionalLogic == null) { if (field.conditionalLogic == null) {
setViewVisibility(field.id, true); setViewVisibility(field.id, true);
@ -1311,7 +1321,6 @@ public class FormsFragment extends Fragment {
private boolean evaluateLogic(GravityField.ConditionalLogic logic) { private boolean evaluateLogic(GravityField.ConditionalLogic logic) {
if (logic.rules == null || logic.rules.isEmpty()) return true; if (logic.rules == null || logic.rules.isEmpty()) return true;
boolean isAll = "all".equalsIgnoreCase(logic.logicType); boolean isAll = "all".equalsIgnoreCase(logic.logicType);
boolean aggregatedResult = isAll; boolean aggregatedResult = isAll;
@ -1364,7 +1373,16 @@ public class FormsFragment extends Fragment {
Object item = ((Spinner) view).getSelectedItem(); Object item = ((Spinner) view).getSelectedItem();
return item != null ? item.toString() : ""; return item != null ? item.toString() : "";
} }
if (view instanceof CheckBox) return ((CheckBox) view).isChecked() ? "1" : ""; // --- VIKTIG ENDRING: HENT TAG-VERDI ---
if (view instanceof CheckBox) {
CheckBox cb = (CheckBox) view;
if (cb.isChecked()) {
// Returner verdien lagret i Tag (f.eks "Ja") i stedet for hardkodet "1"
return cb.getTag() != null ? cb.getTag().toString() : "1";
}
return "";
}
// ----------------------------------------
return ""; return "";
} }
@ -1428,7 +1446,6 @@ public class FormsFragment extends Fragment {
updateStatus("Sender inn..."); updateStatus("Sender inn...");
String cookie = UserManager.getInstance().getCookie(); String cookie = UserManager.getInstance().getCookie();
Log.d(TAG, "Preparing submission payload: " + inputValues.toString()); Log.d(TAG, "Preparing submission payload: " + inputValues.toString());
if (!fileUploads.isEmpty()) { if (!fileUploads.isEmpty()) {
@ -1455,10 +1472,10 @@ public class FormsFragment extends Fragment {
}); });
} else { } else {
try { try {
String errBody = response.body().string(); // --- BEDRE LOGGING FOR 400 FEIL ---
String errBody = response.body() != null ? response.body().string() : "No body";
Log.e(TAG, "Server error body: " + errBody); Log.e(TAG, "Server error body: " + errBody);
// Prøv å vise feilmeldingen fra serveren updateStatus("Feil (" + response.code() + "): " + errBody); // Viser feilmeldingen i UI
updateStatus("Feil (" + response.code() + "): Sjekk logg.");
} catch(Exception e){} } catch(Exception e){}
} }
} }
@ -1545,7 +1562,6 @@ public class FormsFragment extends Fragment {
int userId = user.getUserId(); int userId = user.getUserId();
if (cookie == null) return; if (cookie == null) return;
String searchJson = "{\"field_filters\":[{\"key\":\"created_by\",\"value\":\"" + userId + "\"}]}"; String searchJson = "{\"field_filters\":[{\"key\":\"created_by\",\"value\":\"" + userId + "\"}]}";
String encodedSearch = ""; String encodedSearch = "";
try { try {
@ -1553,7 +1569,6 @@ public class FormsFragment extends Fragment {
} catch (UnsupportedEncodingException e) { e.printStackTrace(); } } catch (UnsupportedEncodingException e) { e.printStackTrace(); }
String url = BASE_URL_GF + "/entries?form_ids=" + formId + "&search=" + encodedSearch; String url = BASE_URL_GF + "/entries?form_ids=" + formId + "&search=" + encodedSearch;
Request request = new Request.Builder().url(url).header("Cookie", cookie).build(); Request request = new Request.Builder().url(url).header("Cookie", cookie).build();
client.newCall(request).enqueue(new okhttp3.Callback() { client.newCall(request).enqueue(new okhttp3.Callback() {
@ -1607,7 +1622,6 @@ public class FormsFragment extends Fragment {
item.setText("Innsendt: " + date); item.setText("Innsendt: " + date);
item.setPadding(10, 20, 10, 20); item.setPadding(10, 20, 10, 20);
item.setBackgroundResource(android.R.drawable.list_selector_background); item.setBackgroundResource(android.R.drawable.list_selector_background);
View line = new View(getContext()); View line = new View(getContext());
line.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 1)); line.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 1));
line.setBackgroundColor(Color.LTGRAY); line.setBackgroundColor(Color.LTGRAY);
@ -1620,7 +1634,6 @@ public class FormsFragment extends Fragment {
private void prefillFormFromHistory(JSONObject latestEntry) { private void prefillFormFromHistory(JSONObject latestEntry) {
if (latestEntry == null) return; if (latestEntry == null) return;
for (Map.Entry<String, View> entry : inputViews.entrySet()) { for (Map.Entry<String, View> entry : inputViews.entrySet()) {
String fieldId = entry.getKey(); String fieldId = entry.getKey();
View view = entry.getValue(); View view = entry.getValue();
@ -1656,9 +1669,20 @@ public class FormsFragment extends Fragment {
private void clearInputs() { private void clearInputs() {
for (View view : inputViews.values()) { for (View view : inputViews.values()) {
if (view instanceof EditText) ((EditText) view).setText(""); if (view instanceof EditText) {
if (view instanceof CheckBox) ((CheckBox) view).setChecked(false); ((EditText) view).setText("");
if (view instanceof Button) ((TextView) view.getTag()).setText("Ingen fil valgt"); } else if (view instanceof CheckBox) {
((CheckBox) view).setChecked(false);
} else if (view instanceof RadioGroup) {
((RadioGroup) view).clearCheck();
} else if (view instanceof Button) {
// Fix: CheckBox inherits from Button, so we must be careful.
// Only cast to TextView if the tag is actually a TextView (File Upload logic)
Object tag = view.getTag();
if (tag instanceof TextView) {
((TextView) tag).setText("Ingen fil valgt");
}
}
} }
fileUploads.clear(); fileUploads.clear();
nestedEntries.clear(); nestedEntries.clear();