Før lenker til tidligere oppføriner
This commit is contained in:
parent
4e67902021
commit
c23b4ba3d3
6 changed files with 867 additions and 535 deletions
|
|
@ -1,15 +1,19 @@
|
|||
package com.kbs.kbsintranett;
|
||||
|
||||
import android.Manifest;
|
||||
import android.animation.LayoutTransition;
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.DatePickerDialog;
|
||||
import android.app.TimePickerDialog;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Typeface;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.Environment;
|
||||
import android.provider.OpenableColumns;
|
||||
import android.text.Editable;
|
||||
import android.text.Html;
|
||||
|
|
@ -18,12 +22,14 @@ import android.text.TextUtils;
|
|||
import android.text.TextWatcher;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.Button;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.EditText;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.RadioButton;
|
||||
|
|
@ -37,6 +43,8 @@ import androidx.activity.result.ActivityResultLauncher;
|
|||
import androidx.activity.result.contract.ActivityResultContracts;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.core.content.FileProvider;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
|
|
@ -46,6 +54,7 @@ import org.json.JSONArray;
|
|||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
|
@ -92,9 +101,11 @@ public class FormsFragment extends Fragment {
|
|||
|
||||
private LinearLayout formContainer;
|
||||
private LinearLayout historyContainer;
|
||||
private View historyWrapper; // Wrapper for historikk-modulen
|
||||
private TextView txtStatus;
|
||||
private TextView lblHistory;
|
||||
private ProgressBar loadingSpinner;
|
||||
private ImageView btnToggleHistory; // NY: Knapp for å vise/skjule historikk
|
||||
|
||||
// --- HOVEDSKJEMA STATE ---
|
||||
private Map<String, View> fieldWrappers = new HashMap<>();
|
||||
|
|
@ -110,9 +121,15 @@ public class FormsFragment extends Fragment {
|
|||
private List<NestedEntry> nestedEntries = new ArrayList<>();
|
||||
private LinearLayout nestedEntriesContainer;
|
||||
private TextView totalAmountView;
|
||||
|
||||
// --- FILOPPLASTING & KAMERA ---
|
||||
private String pendingFileFieldId = null;
|
||||
private boolean isSelectingForChild = false;
|
||||
private Uri currentPhotoUri = null;
|
||||
|
||||
private ActivityResultLauncher<Intent> filePickerLauncher;
|
||||
private ActivityResultLauncher<Uri> takePictureLauncher;
|
||||
private ActivityResultLauncher<String> requestPermissionLauncher;
|
||||
|
||||
private GravityForm currentForm;
|
||||
private final OkHttpClient client = new OkHttpClient();
|
||||
|
|
@ -131,8 +148,26 @@ public class FormsFragment extends Fragment {
|
|||
handleFileSelection(pendingFileFieldId, uri, isSelectingForChild);
|
||||
}
|
||||
}
|
||||
pendingFileFieldId = null;
|
||||
isSelectingForChild = false;
|
||||
}
|
||||
);
|
||||
takePictureLauncher = registerForActivityResult(
|
||||
new ActivityResultContracts.TakePicture(),
|
||||
success -> {
|
||||
if (success && currentPhotoUri != null && pendingFileFieldId != null) {
|
||||
handleFileSelection(pendingFileFieldId, currentPhotoUri, isSelectingForChild);
|
||||
} else if (!success) {
|
||||
currentPhotoUri = null;
|
||||
}
|
||||
}
|
||||
);
|
||||
requestPermissionLauncher = registerForActivityResult(
|
||||
new ActivityResultContracts.RequestPermission(),
|
||||
isGranted -> {
|
||||
if (isGranted) {
|
||||
openCamera();
|
||||
} else {
|
||||
Toast.makeText(getContext(), "Kameratillatelse er påkrevd for å ta bilde.", Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
@ -143,10 +178,29 @@ public class FormsFragment extends Fragment {
|
|||
View view = inflater.inflate(R.layout.fragment_forms, container, false);
|
||||
formContainer = view.findViewById(R.id.form_container);
|
||||
historyContainer = view.findViewById(R.id.historyContainer);
|
||||
historyWrapper = view.findViewById(R.id.history_wrapper);
|
||||
txtStatus = view.findViewById(R.id.txt_status);
|
||||
lblHistory = view.findViewById(R.id.lbl_history);
|
||||
loadingSpinner = view.findViewById(R.id.loading_spinner);
|
||||
|
||||
// --- NY KODE START: Vis/Skjul knapp ---
|
||||
btnToggleHistory = view.findViewById(R.id.btn_toggle_history);
|
||||
if (btnToggleHistory != null) {
|
||||
btnToggleHistory.setOnClickListener(v -> toggleHistoryVisibility());
|
||||
}
|
||||
// --- NY KODE SLUTT ---
|
||||
|
||||
// --- FIKS FOR NULLPOINTER EXCEPTION PÅ LAYOUTTRANSITION ---
|
||||
if (view instanceof ViewGroup) {
|
||||
LayoutTransition transition = ((ViewGroup) view).getLayoutTransition();
|
||||
if (transition == null) {
|
||||
transition = new LayoutTransition();
|
||||
((ViewGroup) view).setLayoutTransition(transition);
|
||||
}
|
||||
transition.enableTransitionType(LayoutTransition.CHANGING);
|
||||
}
|
||||
// ----------------------------------------------------------
|
||||
|
||||
if (formContainer == null) {
|
||||
formContainer = new LinearLayout(getContext());
|
||||
}
|
||||
|
|
@ -161,6 +215,58 @@ public class FormsFragment extends Fragment {
|
|||
return view;
|
||||
}
|
||||
|
||||
// --- UI LOGIKK FOR DELT SKJERM ---
|
||||
|
||||
// Kalles når brukeren interagerer med et felt i skjemaet
|
||||
private void expandFormModule() {
|
||||
if (historyWrapper != null && historyWrapper.getVisibility() == View.VISIBLE) {
|
||||
historyWrapper.setVisibility(View.GONE);
|
||||
|
||||
// Oppdater ikonet til å peke NED (for å vise at man kan hente historikk ned igjen)
|
||||
if (btnToggleHistory != null) {
|
||||
btnToggleHistory.setImageResource(android.R.drawable.arrow_down_float);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NY METODE: Håndterer klikk på pil-knappen
|
||||
private void toggleHistoryVisibility() {
|
||||
if (historyWrapper == null || btnToggleHistory == null) return;
|
||||
|
||||
if (historyWrapper.getVisibility() == View.VISIBLE) {
|
||||
// Skjul historikk (Gå til fullskjerm)
|
||||
historyWrapper.setVisibility(View.GONE);
|
||||
btnToggleHistory.setImageResource(android.R.drawable.arrow_down_float);
|
||||
} else {
|
||||
// Vis historikk (Gå til splitscreen)
|
||||
historyWrapper.setVisibility(View.VISIBLE);
|
||||
btnToggleHistory.setImageResource(android.R.drawable.arrow_up_float);
|
||||
}
|
||||
}
|
||||
|
||||
private void attachInteractionListener(View view) {
|
||||
if (view == null) return;
|
||||
// Touch listener fanger opp klikk før tastaturet kommer opp
|
||||
view.setOnTouchListener((v, event) -> {
|
||||
if (event.getAction() == MotionEvent.ACTION_DOWN) {
|
||||
expandFormModule();
|
||||
}
|
||||
return false; // Return false to allow normal processing
|
||||
});
|
||||
// Focus listener for edittexts etc
|
||||
view.setOnFocusChangeListener((v, hasFocus) -> {
|
||||
if (hasFocus) {
|
||||
expandFormModule();
|
||||
}
|
||||
});
|
||||
// Click listener for buttons/checkboxes
|
||||
if (view.isClickable()) {
|
||||
view.setOnClickListener(v -> expandFormModule());
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------
|
||||
|
||||
private void fetchFormStructure() {
|
||||
if (loadingSpinner != null) loadingSpinner.setVisibility(View.VISIBLE);
|
||||
updateStatus("Laster skjema...");
|
||||
|
|
@ -202,6 +308,12 @@ public class FormsFragment extends Fragment {
|
|||
nestedEntries.clear();
|
||||
updateStatus("");
|
||||
|
||||
// Reset visibility of history on new load (Splitscreen start)
|
||||
if (historyWrapper != null) {
|
||||
historyWrapper.setVisibility(View.VISIBLE);
|
||||
if (btnToggleHistory != null) btnToggleHistory.setImageResource(android.R.drawable.arrow_up_float);
|
||||
}
|
||||
|
||||
TextView title = new TextView(getContext());
|
||||
title.setText(getCleanTitle(form.title));
|
||||
title.setTextSize(24);
|
||||
|
|
@ -219,7 +331,6 @@ public class FormsFragment extends Fragment {
|
|||
}
|
||||
|
||||
if (form.fields == null) return;
|
||||
|
||||
for (GravityField field : form.fields) {
|
||||
if ("hidden".equals(field.type) || field.isHidden || "hidden".equals(field.visibility)) {
|
||||
continue;
|
||||
|
|
@ -326,6 +437,7 @@ public class FormsFragment extends Fragment {
|
|||
btnAdd.setBackgroundColor(Color.parseColor("#53AFE9"));
|
||||
btnAdd.setTextColor(Color.WHITE);
|
||||
btnAdd.setOnClickListener(v -> {
|
||||
expandFormModule(); // Trigger expand
|
||||
int childFormId = 18;
|
||||
if (field.gpnfForm != null) {
|
||||
try {
|
||||
|
|
@ -358,7 +470,6 @@ public class FormsFragment extends Fragment {
|
|||
.setMessage("Laster skjema...")
|
||||
.setCancelable(false)
|
||||
.show();
|
||||
|
||||
RetrofitClient.getApiService().getForm(childFormId).enqueue(new retrofit2.Callback<GravityForm>() {
|
||||
@Override
|
||||
public void onResponse(retrofit2.Call<GravityForm> call, retrofit2.Response<GravityForm> response) {
|
||||
|
|
@ -380,8 +491,6 @@ public class FormsFragment extends Fragment {
|
|||
|
||||
private void showChildFormDialog(GravityForm childForm) {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
|
||||
// FJERNET: builder.setTitle(childForm.title); - Brukeren ønsket ikke tittel i popup
|
||||
|
||||
childInputViews.clear();
|
||||
childRequiredFieldsMap.clear();
|
||||
childFileUploads.clear();
|
||||
|
|
@ -391,10 +500,8 @@ public class FormsFragment extends Fragment {
|
|||
layout.setOrientation(LinearLayout.VERTICAL);
|
||||
layout.setPadding(30, 30, 30, 30);
|
||||
scrollView.addView(layout);
|
||||
|
||||
for (GravityField field : childForm.fields) {
|
||||
if ("hidden".equals(field.type) || field.isHidden) continue;
|
||||
|
||||
LinearLayout wrapper = new LinearLayout(getContext());
|
||||
wrapper.setOrientation(LinearLayout.VERTICAL);
|
||||
wrapper.setPadding(0, 10, 0, 20);
|
||||
|
|
@ -405,7 +512,6 @@ public class FormsFragment extends Fragment {
|
|||
label.setText(lText);
|
||||
label.setTypeface(null, Typeface.BOLD);
|
||||
wrapper.addView(label);
|
||||
|
||||
if ("fileupload".equals(field.type)) {
|
||||
renderFileUploadField(wrapper, field, childInputViews, childRequiredFieldsMap, true);
|
||||
} else if ("product".equals(field.type)) {
|
||||
|
|
@ -479,7 +585,6 @@ public class FormsFragment extends Fragment {
|
|||
// ID 3 = Beskrivelse, ID 4 = Beløp
|
||||
String desc = getInputValueGeneric(childInputViews.get("3"));
|
||||
String price = getInputValueGeneric(childInputViews.get("4"));
|
||||
|
||||
addNestedEntry(entryId, desc, price);
|
||||
dialog.dismiss();
|
||||
} else {
|
||||
|
|
@ -542,27 +647,20 @@ public class FormsFragment extends Fragment {
|
|||
}
|
||||
}
|
||||
|
||||
// --- FELLES METODER ---
|
||||
// --- FELLES METODER (FILE UPLOAD M/ CAMERA STØTTE) ---
|
||||
|
||||
private void renderFileUploadField(LinearLayout container, GravityField field, Map<String, View> viewsMap, Map<String, Boolean> reqMap, boolean isChild) {
|
||||
LinearLayout fileLayout = new LinearLayout(getContext());
|
||||
fileLayout.setOrientation(LinearLayout.HORIZONTAL);
|
||||
|
||||
Button btnUpload = new Button(getContext());
|
||||
btnUpload.setText("Velg fil");
|
||||
btnUpload.setText("Velg fil / Ta bilde");
|
||||
btnUpload.setOnClickListener(v -> {
|
||||
if (filePickerLauncher == null) return;
|
||||
try {
|
||||
// Setter state før vi viser dialog
|
||||
pendingFileFieldId = field.id;
|
||||
isSelectingForChild = isChild;
|
||||
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
|
||||
intent.setType("*/*");
|
||||
String[] mimeTypes = {"image/jpeg", "image/png", "application/pdf"};
|
||||
intent.putExtra(Intent.EXTRA_MIME_TYPES, mimeTypes);
|
||||
filePickerLauncher.launch(intent);
|
||||
} catch (Exception e) {
|
||||
Toast.makeText(getContext(), "Kunne ikke åpne filvelger", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
expandFormModule(); // Trigger expand
|
||||
showFileSourceDialog();
|
||||
});
|
||||
TextView txtFileName = new TextView(getContext());
|
||||
txtFileName.setText("Ingen fil valgt");
|
||||
|
|
@ -578,6 +676,62 @@ public class FormsFragment extends Fragment {
|
|||
reqMap.put(field.id, field.isRequired);
|
||||
}
|
||||
|
||||
// Hjelpemetode for å vise dialog
|
||||
private void showFileSourceDialog() {
|
||||
String[] options = {"Ta bilde", "Velg fil"};
|
||||
new AlertDialog.Builder(getContext())
|
||||
.setTitle("Last opp vedlegg")
|
||||
.setItems(options, (dialog, which) -> {
|
||||
if (which == 0) {
|
||||
// Ta bilde - SJEKKER PERMISSION FØRST
|
||||
if (ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.CAMERA)
|
||||
== PackageManager.PERMISSION_GRANTED) {
|
||||
openCamera();
|
||||
} else {
|
||||
// Spør om lov
|
||||
requestPermissionLauncher.launch(Manifest.permission.CAMERA);
|
||||
}
|
||||
} else {
|
||||
// Velg fil
|
||||
if (filePickerLauncher != null) {
|
||||
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
|
||||
intent.setType("*/*");
|
||||
String[] mimeTypes = {"image/jpeg", "image/png", "application/pdf"};
|
||||
intent.putExtra(Intent.EXTRA_MIME_TYPES, mimeTypes);
|
||||
filePickerLauncher.launch(intent);
|
||||
}
|
||||
}
|
||||
})
|
||||
.show();
|
||||
}
|
||||
|
||||
private void openCamera() {
|
||||
currentPhotoUri = createImageUri();
|
||||
if (currentPhotoUri != null && takePictureLauncher != null) {
|
||||
try {
|
||||
takePictureLauncher.launch(currentPhotoUri);
|
||||
} catch (Exception e) {
|
||||
Toast.makeText(getContext(), "Kunne ikke starte kamera: " + e.getMessage(), Toast.LENGTH_SHORT).show();
|
||||
Log.e(TAG, "Camera launch failed", e);
|
||||
}
|
||||
} else {
|
||||
Toast.makeText(getContext(), "Kunne ikke opprette bildefil", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
|
||||
private Uri createImageUri() {
|
||||
try {
|
||||
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date());
|
||||
String imageFileName = "JPEG_" + timeStamp + "_";
|
||||
File storageDir = requireContext().getExternalFilesDir(Environment.DIRECTORY_PICTURES);
|
||||
File image = File.createTempFile(imageFileName, ".jpg", storageDir);
|
||||
return FileProvider.getUriForFile(requireContext(), "com.kbs.kbsintranett.fileprovider", image);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private void handleFileSelection(String fieldId, Uri uri, boolean isChild) {
|
||||
if (isChild) {
|
||||
childFileUploads.put(fieldId, uri);
|
||||
|
|
@ -631,6 +785,7 @@ public class FormsFragment extends Fragment {
|
|||
timeInput.setClickable(true);
|
||||
timeInput.setHint("00:00");
|
||||
timeInput.setOnClickListener(v -> {
|
||||
expandFormModule(); // Trigger expand
|
||||
Calendar mcurrentTime = Calendar.getInstance();
|
||||
int hour = mcurrentTime.get(Calendar.HOUR_OF_DAY);
|
||||
int minute = mcurrentTime.get(Calendar.MINUTE);
|
||||
|
|
@ -671,6 +826,8 @@ public class FormsFragment extends Fragment {
|
|||
public void onTextChanged(CharSequence s, int start, int before, int count) {}
|
||||
public void afterTextChanged(Editable s) { evaluateAllConditionalLogic(); }
|
||||
});
|
||||
attachInteractionListener(input); // Add listener
|
||||
|
||||
container.addView(input);
|
||||
views.put(field.id, input);
|
||||
req.put(field.id, field.isRequired);
|
||||
|
|
@ -682,6 +839,9 @@ public class FormsFragment extends Fragment {
|
|||
input.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_MULTI_LINE);
|
||||
input.setMinLines(3);
|
||||
input.setGravity(android.view.Gravity.TOP | android.view.Gravity.START);
|
||||
|
||||
attachInteractionListener(input); // Add listener
|
||||
|
||||
container.addView(input);
|
||||
views.put(field.id, input);
|
||||
req.put(field.id, field.isRequired);
|
||||
|
|
@ -694,10 +854,19 @@ public class FormsFragment extends Fragment {
|
|||
RadioButton rb = new RadioButton(getContext());
|
||||
rb.setText(choice.text);
|
||||
rb.setTag(choice.value);
|
||||
// Also trigger expand on RadioButton click
|
||||
rb.setOnClickListener(v -> {
|
||||
expandFormModule();
|
||||
evaluateAllConditionalLogic();
|
||||
});
|
||||
group.addView(rb);
|
||||
}
|
||||
}
|
||||
group.setOnCheckedChangeListener((g, i) -> evaluateAllConditionalLogic());
|
||||
// Fallback listener
|
||||
group.setOnCheckedChangeListener((g, i) -> {
|
||||
expandFormModule();
|
||||
evaluateAllConditionalLogic();
|
||||
});
|
||||
container.addView(group);
|
||||
views.put(field.id, group);
|
||||
req.put(field.id, field.isRequired);
|
||||
|
|
@ -705,6 +874,13 @@ public class FormsFragment extends Fragment {
|
|||
|
||||
private void renderSelectField(LinearLayout container, GravityField field, Map<String, View> views, Map<String, Boolean> req) {
|
||||
Spinner spinner = new Spinner(getContext());
|
||||
// Spinner touch listener is tricky, usually set onTouchListener works
|
||||
spinner.setOnTouchListener((v, event) -> {
|
||||
if (event.getAction() == MotionEvent.ACTION_DOWN) {
|
||||
expandFormModule();
|
||||
}
|
||||
return false;
|
||||
});
|
||||
List<String> labels = new ArrayList<>();
|
||||
labels.add("- Velg -");
|
||||
if (field.choices != null) {
|
||||
|
|
@ -723,10 +899,11 @@ public class FormsFragment extends Fragment {
|
|||
checkBox.setText(cbText);
|
||||
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) -> {
|
||||
expandFormModule();
|
||||
evaluateAllConditionalLogic();
|
||||
});
|
||||
container.addView(checkBox);
|
||||
views.put(inputId, checkBox);
|
||||
req.put(inputId, field.isRequired);
|
||||
|
|
@ -739,17 +916,16 @@ public class FormsFragment extends Fragment {
|
|||
CheckBox checkBox = new CheckBox(getContext());
|
||||
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
|
||||
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) -> {
|
||||
expandFormModule();
|
||||
evaluateAllConditionalLogic();
|
||||
});
|
||||
container.addView(checkBox);
|
||||
views.put(inputDef.id, checkBox);
|
||||
req.put(inputDef.id, false);
|
||||
|
|
@ -776,6 +952,7 @@ public class FormsFragment extends Fragment {
|
|||
dateInput.setClickable(true);
|
||||
dateInput.setHint("dd.mm.yyyy");
|
||||
dateInput.setOnClickListener(v -> {
|
||||
expandFormModule(); // Trigger expand
|
||||
Calendar c = Calendar.getInstance();
|
||||
new DatePickerDialog(getContext(), (view, year, month, dayOfMonth) -> {
|
||||
dateInput.setText(String.format("%02d.%02d.%d", dayOfMonth, month + 1, year));
|
||||
|
|
@ -827,6 +1004,7 @@ public class FormsFragment extends Fragment {
|
|||
else if (lowerSub.contains("etternavn")) subInput.setText(user.getLastName());
|
||||
}
|
||||
|
||||
attachInteractionListener(subInput);
|
||||
container.addView(subInput);
|
||||
views.put(subField.id, subInput);
|
||||
req.put(subField.id, isSubRequired);
|
||||
|
|
@ -895,7 +1073,8 @@ public class FormsFragment extends Fragment {
|
|||
aggregatedResult = aggregatedResult && ruleMatch;
|
||||
if (!aggregatedResult) break;
|
||||
} else {
|
||||
aggregatedResult = aggregatedResult || ruleMatch;
|
||||
aggregatedResult = aggregatedResult ||
|
||||
ruleMatch;
|
||||
if (aggregatedResult) break;
|
||||
}
|
||||
}
|
||||
|
|
@ -936,16 +1115,14 @@ public class FormsFragment extends Fragment {
|
|||
Object item = ((Spinner) view).getSelectedItem();
|
||||
return item != null ? item.toString() : "";
|
||||
}
|
||||
// --- 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 cb.getTag() != null ?
|
||||
cb.getTag().toString() : "1";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
// ----------------------------------------
|
||||
return "";
|
||||
}
|
||||
|
||||
|
|
@ -989,7 +1166,6 @@ public class FormsFragment extends Fragment {
|
|||
}
|
||||
if (!val.isEmpty()) {
|
||||
try {
|
||||
// --- DATO FORMATERING FOR API (Fix 400 Bad Request) ---
|
||||
GravityField fieldDef = getGravityFieldById(fieldId);
|
||||
if (fieldDef != null && "date".equals(fieldDef.type)) {
|
||||
val = formatDateForApi(val);
|
||||
|
|
@ -1035,10 +1211,9 @@ public class FormsFragment extends Fragment {
|
|||
});
|
||||
} else {
|
||||
try {
|
||||
// --- BEDRE LOGGING FOR 400 FEIL ---
|
||||
String errBody = response.body() != null ? response.body().string() : "No body";
|
||||
Log.e(TAG, "Server error body: " + errBody);
|
||||
updateStatus("Feil (" + response.code() + "): " + errBody); // Viser feilmeldingen i UI
|
||||
updateStatus("Feil (" + response.code() + "): " + errBody);
|
||||
} catch(Exception e){}
|
||||
}
|
||||
}
|
||||
|
|
@ -1046,7 +1221,6 @@ public class FormsFragment extends Fragment {
|
|||
}
|
||||
}
|
||||
|
||||
// Konverterer dd.MM.yyyy -> yyyy-MM-dd
|
||||
private String formatDateForApi(String dateStr) {
|
||||
if (dateStr == null || dateStr.isEmpty()) return "";
|
||||
try {
|
||||
|
|
@ -1055,7 +1229,7 @@ public class FormsFragment extends Fragment {
|
|||
SimpleDateFormat apiFormat = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault());
|
||||
return apiFormat.format(date);
|
||||
} catch (Exception e) {
|
||||
return dateStr; // Fallback hvis formatet er ukjent
|
||||
return dateStr;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1110,13 +1284,16 @@ public class FormsFragment extends Fragment {
|
|||
InputStream inputStream = getContext().getContentResolver().openInputStream(uri);
|
||||
String fileName = getFileName(uri);
|
||||
RequestBody requestBody = new RequestBody() {
|
||||
@Override public MediaType contentType() { return MediaType.parse("application/octet-stream"); }
|
||||
@Override public MediaType contentType() { return MediaType.parse("application/octet-stream");
|
||||
}
|
||||
@Override public void writeTo(BufferedSink sink) throws IOException {
|
||||
try (Source source = Okio.source(inputStream)) { sink.writeAll(source); }
|
||||
try (Source source = Okio.source(inputStream)) { sink.writeAll(source);
|
||||
}
|
||||
}
|
||||
};
|
||||
return MultipartBody.Part.createFormData(partName, fileName, requestBody);
|
||||
} catch (Exception e) { return null; }
|
||||
} catch (Exception e) { return null;
|
||||
}
|
||||
}
|
||||
|
||||
private void fetchFormEntries() {
|
||||
|
|
@ -1151,7 +1328,8 @@ public class FormsFragment extends Fragment {
|
|||
if (getActivity() != null) {
|
||||
getActivity().runOnUiThread(() -> {
|
||||
showHistory(entries);
|
||||
if (formId == ID_ANSATTEOPPLYSNINGER && entries.length() > 0) {
|
||||
if (formId == ID_ANSATTEOPPLYSNINGER && entries.length() > 0)
|
||||
{
|
||||
try {
|
||||
prefillFormFromHistory(entries.getJSONObject(0));
|
||||
} catch (JSONException e) { e.printStackTrace(); }
|
||||
|
|
@ -1159,7 +1337,8 @@ public class FormsFragment extends Fragment {
|
|||
});
|
||||
}
|
||||
}
|
||||
} catch (JSONException e) { e.printStackTrace(); }
|
||||
} catch (JSONException e) { e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
@ -1177,14 +1356,21 @@ public class FormsFragment extends Fragment {
|
|||
}
|
||||
|
||||
try {
|
||||
int count = Math.min(entries.length(), 5);
|
||||
// Vis flere oppføringer siden vi nå har scrolle-mulighet øverst
|
||||
int count = Math.min(entries.length(), 20);
|
||||
for (int i = 0; i < count; i++) {
|
||||
JSONObject entry = entries.getJSONObject(i);
|
||||
String date = entry.optString("date_created");
|
||||
|
||||
// Prøv å finne en bedre tittel enn bare dato (f.eks Prosjektnavn eller Sted)
|
||||
String titleText = "Innsendt: " + date;
|
||||
TextView item = new TextView(getContext());
|
||||
item.setText("Innsendt: " + date);
|
||||
item.setText(titleText);
|
||||
item.setPadding(10, 20, 10, 20);
|
||||
item.setBackgroundResource(android.R.drawable.list_selector_background);
|
||||
item.setTextSize(14);
|
||||
// Add click listener to show details
|
||||
item.setOnClickListener(v -> showEntryDetails(entry));
|
||||
View line = new View(getContext());
|
||||
line.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 1));
|
||||
line.setBackgroundColor(Color.LTGRAY);
|
||||
|
|
@ -1192,7 +1378,64 @@ public class FormsFragment extends Fragment {
|
|||
historyContainer.addView(item);
|
||||
historyContainer.addView(line);
|
||||
}
|
||||
} catch (JSONException e) { e.printStackTrace(); }
|
||||
} catch (JSONException e) { e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
// NY METODE: Vis detaljer i dialog
|
||||
private void showEntryDetails(JSONObject entry) {
|
||||
StringBuilder details = new StringBuilder();
|
||||
try {
|
||||
// Loop gjennom alle felter i entry og match med skjema-definisjon
|
||||
// Merk: Entry keys er felt-IDer (f.eks "1", "3.2")
|
||||
|
||||
// Dato
|
||||
details.append("<b>Innsendt:</b> ").append(entry.optString("date_created")).append("<br><br>");
|
||||
// Iterer gjennom feltene i skjema-definisjonen for å få riktig rekkefølge
|
||||
if (currentForm != null && currentForm.fields != null) {
|
||||
for (GravityField field : currentForm.fields) {
|
||||
if ("section".equals(field.type) || "html".equals(field.type) || "captcha".equals(field.type)) continue;
|
||||
String value = "";
|
||||
if (field.inputs != null && !field.inputs.isEmpty()) {
|
||||
// Composite fields (Address, Name)
|
||||
for (GravityField input : field.inputs) {
|
||||
String subVal = entry.optString(input.id);
|
||||
if (!subVal.isEmpty()) {
|
||||
value += " " + subVal;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Standard field
|
||||
value = entry.optString(String.valueOf(field.id));
|
||||
}
|
||||
|
||||
if (!value.trim().isEmpty()) {
|
||||
// For filopplastinger er verdien ofte en URL.
|
||||
if ("fileupload".equals(field.type)) {
|
||||
value = "(Vedlegg)";
|
||||
}
|
||||
|
||||
details.append("<b>").append(field.label).append(":</b><br>")
|
||||
.append(value).append("<br><br>");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
details.append("Kunne ikke vise detaljer.");
|
||||
}
|
||||
|
||||
ScrollView scroll = new ScrollView(getContext());
|
||||
TextView text = new TextView(getContext());
|
||||
text.setText(Html.fromHtml(details.toString(), Html.FROM_HTML_MODE_COMPACT));
|
||||
text.setPadding(40, 40, 40, 40);
|
||||
scroll.addView(text);
|
||||
|
||||
new AlertDialog.Builder(getContext())
|
||||
.setTitle("Detaljer")
|
||||
.setView(scroll)
|
||||
.setPositiveButton("Lukk", null)
|
||||
.show();
|
||||
}
|
||||
|
||||
private void prefillFormFromHistory(JSONObject latestEntry) {
|
||||
|
|
@ -1239,8 +1482,6 @@ public class FormsFragment extends Fragment {
|
|||
} 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");
|
||||
|
|
@ -1253,12 +1494,12 @@ public class FormsFragment extends Fragment {
|
|||
if (totalAmountView != null) totalAmountView.setText("Kr 0,00");
|
||||
}
|
||||
|
||||
// --- HJELPEKLASSE FOR NESTED ENTRIES ---
|
||||
private static class NestedEntry {
|
||||
String id;
|
||||
String description;
|
||||
String price;
|
||||
NestedEntry(String id, String d, String p) { this.id = id; this.description = d; this.price = p; }
|
||||
NestedEntry(String id, String d, String p) { this.id = id; this.description = d; this.price = p;
|
||||
}
|
||||
}
|
||||
|
||||
private void updateStatus(String msg) {
|
||||
|
|
|
|||
|
|
@ -2,194 +2,60 @@ package com.kbs.kbsintranett;
|
|||
|
||||
import android.graphics.Color;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.navigation.Navigation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import retrofit2.Call;
|
||||
import retrofit2.Callback;
|
||||
import retrofit2.Response;
|
||||
|
||||
public class FormsListFragment extends Fragment {
|
||||
|
||||
private static final String TAG = "FormsListFragment";
|
||||
private LinearLayout container;
|
||||
private ProgressBar loadingSpinner;
|
||||
private TextView txtStatus;
|
||||
|
||||
// Regex for å finne tall i starten av tittelen (f.eks "10. Tittel")
|
||||
// Group 1 = Tallet
|
||||
// Group 2 = Resten av teksten (den rene tittelen)
|
||||
private static final Pattern TITLE_PATTERN = Pattern.compile("^(\\d+)[.\\s-]+\\s*(.*)");
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
View view = inflater.inflate(R.layout.fragment_forms, container, false);
|
||||
this.container = view.findViewById(R.id.form_container);
|
||||
this.loadingSpinner = view.findViewById(R.id.loading_spinner);
|
||||
this.txtStatus = view.findViewById(R.id.txt_status);
|
||||
View view = inflater.inflate(R.layout.fragment_forms_list, container, false);
|
||||
LinearLayout formsContainer = view.findViewById(R.id.forms_container);
|
||||
|
||||
View historyTitle = view.findViewById(R.id.historyContainer);
|
||||
if (historyTitle != null) historyTitle.setVisibility(View.GONE);
|
||||
|
||||
LinearLayout mainLayout = view.findViewById(R.id.main_layout);
|
||||
if (mainLayout != null && mainLayout.getChildCount() > 4) {
|
||||
for(int i = 0; i < mainLayout.getChildCount(); i++) {
|
||||
View child = mainLayout.getChildAt(i);
|
||||
if (child instanceof TextView && ((TextView)child).getText().toString().contains("Tidligere")) {
|
||||
child.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Legger til knappene for de ulike skjemaene
|
||||
addFormButton(formsContainer, "1. Ansatteopplysninger", 1);
|
||||
addFormButton(formsContainer, "4. RUH (Rapport om uønsket hendelse)", 4);
|
||||
addFormButton(formsContainer, "9. Sikkerhetskurs / Kompetansebevis", 9);
|
||||
addFormButton(formsContainer, "10. HMS-bekreftelse", 10);
|
||||
addFormButton(formsContainer, "11. Egenmelding", 11);
|
||||
addFormButton(formsContainer, "12. Sjekkliste for firmabil", 12);
|
||||
addFormButton(formsContainer, "14. SJA (Sikker Jobbanalyse)", 14);
|
||||
addFormButton(formsContainer, "15. Fraværsvarsel", 15);
|
||||
addFormButton(formsContainer, "16. Refusjon utlegg", 16);
|
||||
addFormButton(formsContainer, "21. Forberedelse til medarbeidersamtale", 21);
|
||||
addFormButton(formsContainer, "22. Medarbeiderundersøkelse", 22);
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
fetchFormsList();
|
||||
}
|
||||
|
||||
private void fetchFormsList() {
|
||||
if (container != null) container.removeAllViews();
|
||||
if (loadingSpinner != null) loadingSpinner.setVisibility(View.VISIBLE);
|
||||
if (txtStatus != null) txtStatus.setText("");
|
||||
|
||||
// Vi bruker standard-kallet som er raskt og effektivt
|
||||
RetrofitClient.getApiService().getFormsListMap().enqueue(new Callback<Map<String, GravityForm>>() {
|
||||
@Override
|
||||
public void onResponse(Call<Map<String, GravityForm>> call, Response<Map<String, GravityForm>> response) {
|
||||
if (getContext() == null) return;
|
||||
if (loadingSpinner != null) loadingSpinner.setVisibility(View.GONE);
|
||||
|
||||
if (response.isSuccessful() && response.body() != null) {
|
||||
Map<String, GravityForm> formMap = response.body();
|
||||
|
||||
if (formMap.isEmpty()) {
|
||||
if (txtStatus != null) txtStatus.setText("Ingen skjemaer funnet.");
|
||||
return;
|
||||
}
|
||||
|
||||
List<GravityForm> visibleForms = new ArrayList<>();
|
||||
for (GravityForm form : formMap.values()) {
|
||||
// Sjekk om aktiv
|
||||
boolean isActive = form.isActive == null || !"0".equals(form.isActive);
|
||||
|
||||
// Sjekk om vi finner et sorteringstall i tittelen
|
||||
Integer sortOrder = getSortOrderFromTitle(form.title);
|
||||
|
||||
if (form != null && form.title != null && isActive && sortOrder != null) {
|
||||
visibleForms.add(form);
|
||||
}
|
||||
}
|
||||
|
||||
if (visibleForms.isEmpty()) {
|
||||
if (txtStatus != null) txtStatus.setText("Ingen tilgjengelige skjemaer (sjekk nummerering i titler).");
|
||||
return;
|
||||
}
|
||||
|
||||
// Sorter listen basert på tallet i tittelen
|
||||
Collections.sort(visibleForms, new Comparator<GravityForm>() {
|
||||
@Override
|
||||
public int compare(GravityForm f1, GravityForm f2) {
|
||||
return Integer.compare(getSortOrderFromTitle(f1.title), getSortOrderFromTitle(f2.title));
|
||||
}
|
||||
});
|
||||
|
||||
for (GravityForm form : visibleForms) {
|
||||
addFormButton(form);
|
||||
}
|
||||
|
||||
} else {
|
||||
if (txtStatus != null) txtStatus.setText("Kunne ikke laste listen (Kode " + response.code() + ")");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Call<Map<String, GravityForm>> call, Throwable t) {
|
||||
if (getContext() == null) return;
|
||||
if (loadingSpinner != null) loadingSpinner.setVisibility(View.GONE);
|
||||
if (txtStatus != null) txtStatus.setText("Nettverksfeil: " + t.getMessage());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Henter ut tallet fra starten av tittelen.
|
||||
* Returnerer null hvis tittelen ikke starter med et tall.
|
||||
*/
|
||||
private Integer getSortOrderFromTitle(String title) {
|
||||
if (title == null) return null;
|
||||
Matcher m = TITLE_PATTERN.matcher(title.trim());
|
||||
if (m.find()) {
|
||||
try {
|
||||
return Integer.parseInt(m.group(1));
|
||||
} catch (NumberFormatException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return null; // Ingen tall funnet -> Skjules
|
||||
}
|
||||
|
||||
/**
|
||||
* Henter ut selve navnet på skjemaet (uten tallet foran).
|
||||
* "10. Ansatte" -> "Ansatte"
|
||||
*/
|
||||
private String getCleanTitle(String title) {
|
||||
if (title == null) return "";
|
||||
Matcher m = TITLE_PATTERN.matcher(title.trim());
|
||||
if (m.find()) {
|
||||
// Group 2 er resten av teksten etter tallet og punktum/mellomrom
|
||||
return m.group(2);
|
||||
}
|
||||
return title; // Fallback hvis regex ikke matcher (skal ikke skje pga filtreringen over)
|
||||
}
|
||||
|
||||
private void addFormButton(GravityForm form) {
|
||||
Button button = new Button(getContext());
|
||||
|
||||
// VIS VASKET TITTEL PÅ KNAPPEN
|
||||
String displayTitle = getCleanTitle(form.title);
|
||||
button.setText(displayTitle.toUpperCase());
|
||||
|
||||
button.setTextColor(Color.WHITE);
|
||||
button.setBackgroundColor(Color.parseColor("#0069B3")); // KBS Blå
|
||||
button.setTextSize(14);
|
||||
button.setPadding(30, 30, 30, 30);
|
||||
|
||||
button.setOnClickListener(v -> {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putInt("formId", form.id);
|
||||
Navigation.findNavController(v).navigate(R.id.action_formsListFragment_to_formsDetailFragment, bundle);
|
||||
});
|
||||
private void addFormButton(LinearLayout container, String title, int formId) {
|
||||
Button btn = new Button(getContext());
|
||||
btn.setText(title);
|
||||
btn.setBackgroundColor(Color.parseColor("#0069B3")); // KBS Blå
|
||||
btn.setTextColor(Color.WHITE);
|
||||
btn.setPadding(30, 30, 30, 30);
|
||||
|
||||
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
);
|
||||
params.setMargins(0, 0, 0, 20);
|
||||
button.setLayoutParams(params);
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
params.setMargins(0, 0, 0, 20); // Litt avstand mellom knappene
|
||||
btn.setLayoutParams(params);
|
||||
|
||||
container.addView(button);
|
||||
btn.setOnClickListener(v -> {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putInt("formId", formId);
|
||||
// HER VAR FEILEN: Endret R.id.nav_forms til riktig action ID
|
||||
Navigation.findNavController(v).navigate(R.id.action_formsListFragment_to_formsDetailFragment, bundle);
|
||||
});
|
||||
|
||||
container.addView(btn);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,74 +1,104 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:padding="16dp"
|
||||
android:background="@android:color/white">
|
||||
android:orientation="vertical"
|
||||
android:background="#F5F5F5"
|
||||
tools:context=".FormsFragment">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/main_layout"
|
||||
android:id="@+id/history_wrapper"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Skjema"
|
||||
android:textSize="24sp"
|
||||
android:textStyle="bold"
|
||||
android:layout_marginBottom="16dp"/>
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/loading_spinner"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:visibility="visible" />
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="3"
|
||||
android:orientation="vertical"
|
||||
android:background="#FFFFFF"
|
||||
android:elevation="4dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:padding="16dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/lbl_history"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Tidligere innsendinger:"
|
||||
android:text="Tidligere innsendinger"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_marginBottom="5dp"/>
|
||||
android:textColor="#333333"
|
||||
android:layout_marginBottom="10dp"/>
|
||||
|
||||
<ScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/historyContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:layout_marginBottom="20dp"/>
|
||||
android:orientation="vertical" />
|
||||
</ScrollView>
|
||||
</LinearLayout>
|
||||
|
||||
<View
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="2dp"
|
||||
android:background="#0069B3"
|
||||
android:layout_marginBottom="20dp"/>
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="7"
|
||||
android:orientation="vertical"
|
||||
android:background="#FFFFFF"
|
||||
android:elevation="4dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical"
|
||||
android:padding="8dp"
|
||||
android:background="#FAFAFA">
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/loading_spinner"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:visibility="gone"
|
||||
android:layout_marginEnd="8dp"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:id="@+id/txt_status"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Ny innsending:"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold"
|
||||
android:layout_marginBottom="10dp"/>
|
||||
android:layout_weight="1"
|
||||
android:textColor="#666666"
|
||||
android:textSize="12sp"
|
||||
android:text="" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/btn_toggle_history"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:src="@android:drawable/arrow_up_float"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:padding="4dp"
|
||||
android:contentDescription="Vis/Skjul historikk"
|
||||
app:tint="#666666" />
|
||||
</LinearLayout>
|
||||
|
||||
<ScrollView
|
||||
android:id="@+id/form_scroll_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:padding="16dp"
|
||||
android:fillViewport="true">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/form_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/txt_status"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="10dp"
|
||||
android:textColor="#D32F2F"
|
||||
android:gravity="center" />
|
||||
|
||||
android:orientation="vertical"
|
||||
android:paddingBottom="40dp">
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
</ScrollView>
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
30
app/src/main/res/layout/fragment_forms_list.xml
Normal file
30
app/src/main/res/layout/fragment_forms_list.xml
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/main_layout" android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp"
|
||||
android:background="#F5F5F5">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/header_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Skjemaer"
|
||||
android:textSize="24sp"
|
||||
android:textStyle="bold"
|
||||
android:layout_marginBottom="20dp"
|
||||
android:textColor="#333333"/>
|
||||
|
||||
<ScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/forms_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical" />
|
||||
</ScrollView>
|
||||
|
||||
</LinearLayout>
|
||||
4
app/src/main/res/xml/file_paths.xml
Normal file
4
app/src/main/res/xml/file_paths.xml
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<paths>
|
||||
<external-files-path name="my_images" path="Pictures" />
|
||||
</paths>
|
||||
|
|
@ -198,6 +198,17 @@ FILSTI: app\src\main\AndroidManifest.xml
|
|||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</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>
|
||||
|
||||
</manifest>
|
||||
|
|
@ -437,16 +448,20 @@ FILSTI: app\src\main\java\com\kbs\kbsintranett\FormsFragment.java
|
|||
============================================================
|
||||
package com.kbs.kbsintranett;
|
||||
|
||||
import android.Manifest;
|
||||
import android.animation.LayoutTransition;
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.DatePickerDialog;
|
||||
import android.app.TimePickerDialog;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Typeface;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.Environment;
|
||||
import android.provider.OpenableColumns;
|
||||
import android.text.Editable;
|
||||
import android.text.Html;
|
||||
|
|
@ -455,6 +470,7 @@ import android.text.TextUtils;
|
|||
import android.text.TextWatcher;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ArrayAdapter;
|
||||
|
|
@ -474,6 +490,8 @@ import androidx.activity.result.ActivityResultLauncher;
|
|||
import androidx.activity.result.contract.ActivityResultContracts;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.core.content.FileProvider;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
|
|
@ -483,6 +501,7 @@ import org.json.JSONArray;
|
|||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
|
@ -529,6 +548,7 @@ public class FormsFragment extends Fragment {
|
|||
|
||||
private LinearLayout formContainer;
|
||||
private LinearLayout historyContainer;
|
||||
private View historyWrapper; // Wrapper for historikk-modulen som skal skjules
|
||||
private TextView txtStatus;
|
||||
private TextView lblHistory;
|
||||
private ProgressBar loadingSpinner;
|
||||
|
|
@ -547,9 +567,15 @@ public class FormsFragment extends Fragment {
|
|||
private List<NestedEntry> nestedEntries = new ArrayList<>();
|
||||
private LinearLayout nestedEntriesContainer;
|
||||
private TextView totalAmountView;
|
||||
|
||||
// --- FILOPPLASTING & KAMERA ---
|
||||
private String pendingFileFieldId = null;
|
||||
private boolean isSelectingForChild = false;
|
||||
private Uri currentPhotoUri = null;
|
||||
|
||||
private ActivityResultLauncher<Intent> filePickerLauncher;
|
||||
private ActivityResultLauncher<Uri> takePictureLauncher;
|
||||
private ActivityResultLauncher<String> requestPermissionLauncher;
|
||||
|
||||
private GravityForm currentForm;
|
||||
private final OkHttpClient client = new OkHttpClient();
|
||||
|
|
@ -559,6 +585,7 @@ public class FormsFragment extends Fragment {
|
|||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
filePickerLauncher = registerForActivityResult(
|
||||
new ActivityResultContracts.StartActivityForResult(),
|
||||
result -> {
|
||||
|
|
@ -568,8 +595,28 @@ public class FormsFragment extends Fragment {
|
|||
handleFileSelection(pendingFileFieldId, uri, isSelectingForChild);
|
||||
}
|
||||
}
|
||||
pendingFileFieldId = null;
|
||||
isSelectingForChild = false;
|
||||
}
|
||||
);
|
||||
|
||||
takePictureLauncher = registerForActivityResult(
|
||||
new ActivityResultContracts.TakePicture(),
|
||||
success -> {
|
||||
if (success && currentPhotoUri != null && pendingFileFieldId != null) {
|
||||
handleFileSelection(pendingFileFieldId, currentPhotoUri, isSelectingForChild);
|
||||
} else if (!success) {
|
||||
currentPhotoUri = null;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
requestPermissionLauncher = registerForActivityResult(
|
||||
new ActivityResultContracts.RequestPermission(),
|
||||
isGranted -> {
|
||||
if (isGranted) {
|
||||
openCamera();
|
||||
} else {
|
||||
Toast.makeText(getContext(), "Kameratillatelse er påkrevd for å ta bilde.", Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
@ -578,12 +625,26 @@ public class FormsFragment extends Fragment {
|
|||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
View view = inflater.inflate(R.layout.fragment_forms, container, false);
|
||||
|
||||
formContainer = view.findViewById(R.id.form_container);
|
||||
historyContainer = view.findViewById(R.id.historyContainer);
|
||||
historyWrapper = view.findViewById(R.id.history_wrapper); // Ny referanse
|
||||
txtStatus = view.findViewById(R.id.txt_status);
|
||||
lblHistory = view.findViewById(R.id.lbl_history);
|
||||
loadingSpinner = view.findViewById(R.id.loading_spinner);
|
||||
|
||||
// --- FIKS FOR NULLPOINTER EXCEPTION ---
|
||||
// Vi sjekker om LayoutTransition finnes, hvis ikke lager vi en ny.
|
||||
if (view instanceof ViewGroup) {
|
||||
LayoutTransition transition = ((ViewGroup) view).getLayoutTransition();
|
||||
if (transition == null) {
|
||||
transition = new LayoutTransition();
|
||||
((ViewGroup) view).setLayoutTransition(transition);
|
||||
}
|
||||
transition.enableTransitionType(LayoutTransition.CHANGING);
|
||||
}
|
||||
// --------------------------------------
|
||||
|
||||
if (formContainer == null) {
|
||||
formContainer = new LinearLayout(getContext());
|
||||
}
|
||||
|
|
@ -598,6 +659,41 @@ public class FormsFragment extends Fragment {
|
|||
return view;
|
||||
}
|
||||
|
||||
// --- UI LOGIKK FOR DELT SKJERM ---
|
||||
|
||||
// Kalles når brukeren interagerer med et felt i skjemaet
|
||||
private void expandFormModule() {
|
||||
if (historyWrapper != null && historyWrapper.getVisibility() == View.VISIBLE) {
|
||||
historyWrapper.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
private void attachInteractionListener(View view) {
|
||||
if (view == null) return;
|
||||
|
||||
// Touch listener fanger opp klikk før tastaturet kommer opp
|
||||
view.setOnTouchListener((v, event) -> {
|
||||
if (event.getAction() == MotionEvent.ACTION_DOWN) {
|
||||
expandFormModule();
|
||||
}
|
||||
return false; // Return false to allow normal processing
|
||||
});
|
||||
|
||||
// Focus listener for edittexts etc
|
||||
view.setOnFocusChangeListener((v, hasFocus) -> {
|
||||
if (hasFocus) {
|
||||
expandFormModule();
|
||||
}
|
||||
});
|
||||
|
||||
// Click listener for buttons/checkboxes
|
||||
if (view.isClickable()) {
|
||||
view.setOnClickListener(v -> expandFormModule());
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------
|
||||
|
||||
private void fetchFormStructure() {
|
||||
if (loadingSpinner != null) loadingSpinner.setVisibility(View.VISIBLE);
|
||||
updateStatus("Laster skjema...");
|
||||
|
|
@ -639,6 +735,9 @@ public class FormsFragment extends Fragment {
|
|||
nestedEntries.clear();
|
||||
updateStatus("");
|
||||
|
||||
// Reset visibility of history on new load
|
||||
if (historyWrapper != null) historyWrapper.setVisibility(View.VISIBLE);
|
||||
|
||||
TextView title = new TextView(getContext());
|
||||
title.setText(getCleanTitle(form.title));
|
||||
title.setTextSize(24);
|
||||
|
|
@ -763,6 +862,7 @@ public class FormsFragment extends Fragment {
|
|||
btnAdd.setBackgroundColor(Color.parseColor("#53AFE9"));
|
||||
btnAdd.setTextColor(Color.WHITE);
|
||||
btnAdd.setOnClickListener(v -> {
|
||||
expandFormModule(); // Trigger expand
|
||||
int childFormId = 18;
|
||||
if (field.gpnfForm != null) {
|
||||
try {
|
||||
|
|
@ -817,7 +917,6 @@ public class FormsFragment extends Fragment {
|
|||
|
||||
private void showChildFormDialog(GravityForm childForm) {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
|
||||
// FJERNET: builder.setTitle(childForm.title); - Brukeren ønsket ikke tittel i popup
|
||||
|
||||
childInputViews.clear();
|
||||
childRequiredFieldsMap.clear();
|
||||
|
|
@ -979,27 +1078,20 @@ public class FormsFragment extends Fragment {
|
|||
}
|
||||
}
|
||||
|
||||
// --- FELLES METODER ---
|
||||
// --- FELLES METODER (FILE UPLOAD M/ CAMERA STØTTE) ---
|
||||
|
||||
private void renderFileUploadField(LinearLayout container, GravityField field, Map<String, View> viewsMap, Map<String, Boolean> reqMap, boolean isChild) {
|
||||
LinearLayout fileLayout = new LinearLayout(getContext());
|
||||
fileLayout.setOrientation(LinearLayout.HORIZONTAL);
|
||||
|
||||
Button btnUpload = new Button(getContext());
|
||||
btnUpload.setText("Velg fil");
|
||||
btnUpload.setText("Velg fil / Ta bilde");
|
||||
btnUpload.setOnClickListener(v -> {
|
||||
if (filePickerLauncher == null) return;
|
||||
try {
|
||||
// Setter state før vi viser dialog
|
||||
pendingFileFieldId = field.id;
|
||||
isSelectingForChild = isChild;
|
||||
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
|
||||
intent.setType("*/*");
|
||||
String[] mimeTypes = {"image/jpeg", "image/png", "application/pdf"};
|
||||
intent.putExtra(Intent.EXTRA_MIME_TYPES, mimeTypes);
|
||||
filePickerLauncher.launch(intent);
|
||||
} catch (Exception e) {
|
||||
Toast.makeText(getContext(), "Kunne ikke åpne filvelger", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
expandFormModule(); // Trigger expand
|
||||
showFileSourceDialog();
|
||||
});
|
||||
TextView txtFileName = new TextView(getContext());
|
||||
txtFileName.setText("Ingen fil valgt");
|
||||
|
|
@ -1015,6 +1107,63 @@ public class FormsFragment extends Fragment {
|
|||
reqMap.put(field.id, field.isRequired);
|
||||
}
|
||||
|
||||
// Hjelpemetode for å vise dialog
|
||||
private void showFileSourceDialog() {
|
||||
String[] options = {"Ta bilde", "Velg fil"};
|
||||
new AlertDialog.Builder(getContext())
|
||||
.setTitle("Last opp vedlegg")
|
||||
.setItems(options, (dialog, which) -> {
|
||||
if (which == 0) {
|
||||
// Ta bilde - SJEKKER PERMISSION FØRST
|
||||
if (ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.CAMERA)
|
||||
== PackageManager.PERMISSION_GRANTED) {
|
||||
openCamera();
|
||||
} else {
|
||||
// Spør om lov
|
||||
requestPermissionLauncher.launch(Manifest.permission.CAMERA);
|
||||
}
|
||||
} else {
|
||||
// Velg fil
|
||||
if (filePickerLauncher != null) {
|
||||
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
|
||||
intent.setType("*/*");
|
||||
String[] mimeTypes = {"image/jpeg", "image/png", "application/pdf"};
|
||||
intent.putExtra(Intent.EXTRA_MIME_TYPES, mimeTypes);
|
||||
filePickerLauncher.launch(intent);
|
||||
}
|
||||
}
|
||||
})
|
||||
.show();
|
||||
}
|
||||
|
||||
private void openCamera() {
|
||||
currentPhotoUri = createImageUri();
|
||||
if (currentPhotoUri != null && takePictureLauncher != null) {
|
||||
try {
|
||||
takePictureLauncher.launch(currentPhotoUri);
|
||||
} catch (Exception e) {
|
||||
Toast.makeText(getContext(), "Kunne ikke starte kamera: " + e.getMessage(), Toast.LENGTH_SHORT).show();
|
||||
Log.e(TAG, "Camera launch failed", e);
|
||||
}
|
||||
} else {
|
||||
Toast.makeText(getContext(), "Kunne ikke opprette bildefil", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
|
||||
private Uri createImageUri() {
|
||||
try {
|
||||
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date());
|
||||
String imageFileName = "JPEG_" + timeStamp + "_";
|
||||
File storageDir = requireContext().getExternalFilesDir(Environment.DIRECTORY_PICTURES);
|
||||
File image = File.createTempFile(imageFileName, ".jpg", storageDir);
|
||||
|
||||
return FileProvider.getUriForFile(requireContext(), "com.kbs.kbsintranett.fileprovider", image);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private void handleFileSelection(String fieldId, Uri uri, boolean isChild) {
|
||||
if (isChild) {
|
||||
childFileUploads.put(fieldId, uri);
|
||||
|
|
@ -1068,6 +1217,7 @@ public class FormsFragment extends Fragment {
|
|||
timeInput.setClickable(true);
|
||||
timeInput.setHint("00:00");
|
||||
timeInput.setOnClickListener(v -> {
|
||||
expandFormModule(); // Trigger expand
|
||||
Calendar mcurrentTime = Calendar.getInstance();
|
||||
int hour = mcurrentTime.get(Calendar.HOUR_OF_DAY);
|
||||
int minute = mcurrentTime.get(Calendar.MINUTE);
|
||||
|
|
@ -1108,6 +1258,9 @@ public class FormsFragment extends Fragment {
|
|||
public void onTextChanged(CharSequence s, int start, int before, int count) {}
|
||||
public void afterTextChanged(Editable s) { evaluateAllConditionalLogic(); }
|
||||
});
|
||||
|
||||
attachInteractionListener(input); // Add listener
|
||||
|
||||
container.addView(input);
|
||||
views.put(field.id, input);
|
||||
req.put(field.id, field.isRequired);
|
||||
|
|
@ -1119,6 +1272,9 @@ public class FormsFragment extends Fragment {
|
|||
input.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_MULTI_LINE);
|
||||
input.setMinLines(3);
|
||||
input.setGravity(android.view.Gravity.TOP | android.view.Gravity.START);
|
||||
|
||||
attachInteractionListener(input); // Add listener
|
||||
|
||||
container.addView(input);
|
||||
views.put(field.id, input);
|
||||
req.put(field.id, field.isRequired);
|
||||
|
|
@ -1131,10 +1287,20 @@ public class FormsFragment extends Fragment {
|
|||
RadioButton rb = new RadioButton(getContext());
|
||||
rb.setText(choice.text);
|
||||
rb.setTag(choice.value);
|
||||
// Also trigger expand on RadioButton click
|
||||
rb.setOnClickListener(v -> {
|
||||
expandFormModule();
|
||||
evaluateAllConditionalLogic();
|
||||
});
|
||||
group.addView(rb);
|
||||
}
|
||||
}
|
||||
group.setOnCheckedChangeListener((g, i) -> evaluateAllConditionalLogic());
|
||||
// Fallback listener
|
||||
group.setOnCheckedChangeListener((g, i) -> {
|
||||
expandFormModule();
|
||||
evaluateAllConditionalLogic();
|
||||
});
|
||||
|
||||
container.addView(group);
|
||||
views.put(field.id, group);
|
||||
req.put(field.id, field.isRequired);
|
||||
|
|
@ -1142,6 +1308,14 @@ public class FormsFragment extends Fragment {
|
|||
|
||||
private void renderSelectField(LinearLayout container, GravityField field, Map<String, View> views, Map<String, Boolean> req) {
|
||||
Spinner spinner = new Spinner(getContext());
|
||||
// Spinner touch listener is tricky, usually set onTouchListener works
|
||||
spinner.setOnTouchListener((v, event) -> {
|
||||
if (event.getAction() == MotionEvent.ACTION_DOWN) {
|
||||
expandFormModule();
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
List<String> labels = new ArrayList<>();
|
||||
labels.add("- Velg -");
|
||||
if (field.choices != null) {
|
||||
|
|
@ -1160,10 +1334,13 @@ public class FormsFragment extends Fragment {
|
|||
checkBox.setText(cbText);
|
||||
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) -> {
|
||||
expandFormModule();
|
||||
evaluateAllConditionalLogic();
|
||||
});
|
||||
|
||||
container.addView(checkBox);
|
||||
views.put(inputId, checkBox);
|
||||
req.put(inputId, field.isRequired);
|
||||
|
|
@ -1176,17 +1353,16 @@ public class FormsFragment extends Fragment {
|
|||
CheckBox checkBox = new CheckBox(getContext());
|
||||
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) -> {
|
||||
expandFormModule();
|
||||
evaluateAllConditionalLogic();
|
||||
});
|
||||
container.addView(checkBox);
|
||||
views.put(inputDef.id, checkBox);
|
||||
req.put(inputDef.id, false);
|
||||
|
|
@ -1213,6 +1389,7 @@ public class FormsFragment extends Fragment {
|
|||
dateInput.setClickable(true);
|
||||
dateInput.setHint("dd.mm.yyyy");
|
||||
dateInput.setOnClickListener(v -> {
|
||||
expandFormModule(); // Trigger expand
|
||||
Calendar c = Calendar.getInstance();
|
||||
new DatePickerDialog(getContext(), (view, year, month, dayOfMonth) -> {
|
||||
dateInput.setText(String.format("%02d.%02d.%d", dayOfMonth, month + 1, year));
|
||||
|
|
@ -1264,6 +1441,8 @@ public class FormsFragment extends Fragment {
|
|||
else if (lowerSub.contains("etternavn")) subInput.setText(user.getLastName());
|
||||
}
|
||||
|
||||
attachInteractionListener(subInput);
|
||||
|
||||
container.addView(subInput);
|
||||
views.put(subField.id, subInput);
|
||||
req.put(subField.id, isSubRequired);
|
||||
|
|
@ -1373,16 +1552,13 @@ public class FormsFragment extends Fragment {
|
|||
Object item = ((Spinner) view).getSelectedItem();
|
||||
return item != null ? item.toString() : "";
|
||||
}
|
||||
// --- 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 "";
|
||||
}
|
||||
|
||||
|
|
@ -1426,7 +1602,6 @@ public class FormsFragment extends Fragment {
|
|||
}
|
||||
if (!val.isEmpty()) {
|
||||
try {
|
||||
// --- DATO FORMATERING FOR API (Fix 400 Bad Request) ---
|
||||
GravityField fieldDef = getGravityFieldById(fieldId);
|
||||
if (fieldDef != null && "date".equals(fieldDef.type)) {
|
||||
val = formatDateForApi(val);
|
||||
|
|
@ -1472,10 +1647,9 @@ public class FormsFragment extends Fragment {
|
|||
});
|
||||
} else {
|
||||
try {
|
||||
// --- BEDRE LOGGING FOR 400 FEIL ---
|
||||
String errBody = response.body() != null ? response.body().string() : "No body";
|
||||
Log.e(TAG, "Server error body: " + errBody);
|
||||
updateStatus("Feil (" + response.code() + "): " + errBody); // Viser feilmeldingen i UI
|
||||
updateStatus("Feil (" + response.code() + "): " + errBody);
|
||||
} catch(Exception e){}
|
||||
}
|
||||
}
|
||||
|
|
@ -1483,7 +1657,6 @@ public class FormsFragment extends Fragment {
|
|||
}
|
||||
}
|
||||
|
||||
// Konverterer dd.MM.yyyy -> yyyy-MM-dd
|
||||
private String formatDateForApi(String dateStr) {
|
||||
if (dateStr == null || dateStr.isEmpty()) return "";
|
||||
try {
|
||||
|
|
@ -1492,7 +1665,7 @@ public class FormsFragment extends Fragment {
|
|||
SimpleDateFormat apiFormat = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault());
|
||||
return apiFormat.format(date);
|
||||
} catch (Exception e) {
|
||||
return dateStr; // Fallback hvis formatet er ukjent
|
||||
return dateStr;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1614,14 +1787,24 @@ public class FormsFragment extends Fragment {
|
|||
}
|
||||
|
||||
try {
|
||||
int count = Math.min(entries.length(), 5);
|
||||
// Vis flere oppføringer siden vi nå har scrolle-mulighet øverst
|
||||
int count = Math.min(entries.length(), 20);
|
||||
for (int i = 0; i < count; i++) {
|
||||
JSONObject entry = entries.getJSONObject(i);
|
||||
String date = entry.optString("date_created");
|
||||
|
||||
// Prøv å finne en bedre tittel enn bare dato (f.eks Prosjektnavn eller Sted)
|
||||
String titleText = "Innsendt: " + date;
|
||||
|
||||
TextView item = new TextView(getContext());
|
||||
item.setText("Innsendt: " + date);
|
||||
item.setText(titleText);
|
||||
item.setPadding(10, 20, 10, 20);
|
||||
item.setBackgroundResource(android.R.drawable.list_selector_background);
|
||||
item.setTextSize(14);
|
||||
|
||||
// Add click listener to show details
|
||||
item.setOnClickListener(v -> showEntryDetails(entry));
|
||||
|
||||
View line = new View(getContext());
|
||||
line.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 1));
|
||||
line.setBackgroundColor(Color.LTGRAY);
|
||||
|
|
@ -1632,6 +1815,64 @@ public class FormsFragment extends Fragment {
|
|||
} catch (JSONException e) { e.printStackTrace(); }
|
||||
}
|
||||
|
||||
// NY METODE: Vis detaljer i dialog
|
||||
private void showEntryDetails(JSONObject entry) {
|
||||
StringBuilder details = new StringBuilder();
|
||||
try {
|
||||
// Loop gjennom alle felter i entry og match med skjema-definisjon
|
||||
// Merk: Entry keys er felt-IDer (f.eks "1", "3.2")
|
||||
|
||||
// Dato
|
||||
details.append("<b>Innsendt:</b> ").append(entry.optString("date_created")).append("<br><br>");
|
||||
|
||||
// Iterer gjennom feltene i skjema-definisjonen for å få riktig rekkefølge
|
||||
if (currentForm != null && currentForm.fields != null) {
|
||||
for (GravityField field : currentForm.fields) {
|
||||
if ("section".equals(field.type) || "html".equals(field.type) || "captcha".equals(field.type)) continue;
|
||||
|
||||
String value = "";
|
||||
if (field.inputs != null && !field.inputs.isEmpty()) {
|
||||
// Composite fields (Address, Name)
|
||||
for (GravityField input : field.inputs) {
|
||||
String subVal = entry.optString(input.id);
|
||||
if (!subVal.isEmpty()) {
|
||||
value += " " + subVal;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Standard field
|
||||
value = entry.optString(String.valueOf(field.id));
|
||||
}
|
||||
|
||||
if (!value.trim().isEmpty()) {
|
||||
// For filopplastinger er verdien ofte en URL.
|
||||
if ("fileupload".equals(field.type)) {
|
||||
value = "(Vedlegg)";
|
||||
}
|
||||
|
||||
details.append("<b>").append(field.label).append(":</b><br>")
|
||||
.append(value).append("<br><br>");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
details.append("Kunne ikke vise detaljer.");
|
||||
}
|
||||
|
||||
ScrollView scroll = new ScrollView(getContext());
|
||||
TextView text = new TextView(getContext());
|
||||
text.setText(Html.fromHtml(details.toString(), Html.FROM_HTML_MODE_COMPACT));
|
||||
text.setPadding(40, 40, 40, 40);
|
||||
scroll.addView(text);
|
||||
|
||||
new AlertDialog.Builder(getContext())
|
||||
.setTitle("Detaljer")
|
||||
.setView(scroll)
|
||||
.setPositiveButton("Lukk", null)
|
||||
.show();
|
||||
}
|
||||
|
||||
private void prefillFormFromHistory(JSONObject latestEntry) {
|
||||
if (latestEntry == null) return;
|
||||
for (Map.Entry<String, View> entry : inputViews.entrySet()) {
|
||||
|
|
@ -1676,8 +1917,6 @@ public class FormsFragment extends Fragment {
|
|||
} 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");
|
||||
|
|
@ -1690,7 +1929,6 @@ public class FormsFragment extends Fragment {
|
|||
if (totalAmountView != null) totalAmountView.setText("Kr 0,00");
|
||||
}
|
||||
|
||||
// --- HJELPEKLASSE FOR NESTED ENTRIES ---
|
||||
private static class NestedEntry {
|
||||
String id;
|
||||
String description;
|
||||
|
|
@ -1712,195 +1950,59 @@ package com.kbs.kbsintranett;
|
|||
|
||||
import android.graphics.Color;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.navigation.Navigation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import retrofit2.Call;
|
||||
import retrofit2.Callback;
|
||||
import retrofit2.Response;
|
||||
|
||||
public class FormsListFragment extends Fragment {
|
||||
|
||||
private static final String TAG = "FormsListFragment";
|
||||
private LinearLayout container;
|
||||
private ProgressBar loadingSpinner;
|
||||
private TextView txtStatus;
|
||||
|
||||
// Regex for å finne tall i starten av tittelen (f.eks "10. Tittel")
|
||||
// Group 1 = Tallet
|
||||
// Group 2 = Resten av teksten (den rene tittelen)
|
||||
private static final Pattern TITLE_PATTERN = Pattern.compile("^(\\d+)[.\\s-]+\\s*(.*)");
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
View view = inflater.inflate(R.layout.fragment_forms, container, false);
|
||||
this.container = view.findViewById(R.id.form_container);
|
||||
this.loadingSpinner = view.findViewById(R.id.loading_spinner);
|
||||
this.txtStatus = view.findViewById(R.id.txt_status);
|
||||
View view = inflater.inflate(R.layout.fragment_forms_list, container, false);
|
||||
LinearLayout formsContainer = view.findViewById(R.id.forms_container);
|
||||
|
||||
View historyTitle = view.findViewById(R.id.historyContainer);
|
||||
if (historyTitle != null) historyTitle.setVisibility(View.GONE);
|
||||
|
||||
LinearLayout mainLayout = view.findViewById(R.id.main_layout);
|
||||
if (mainLayout != null && mainLayout.getChildCount() > 4) {
|
||||
for(int i = 0; i < mainLayout.getChildCount(); i++) {
|
||||
View child = mainLayout.getChildAt(i);
|
||||
if (child instanceof TextView && ((TextView)child).getText().toString().contains("Tidligere")) {
|
||||
child.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
addFormButton(formsContainer, "1. Ansatteopplysninger", 1);
|
||||
addFormButton(formsContainer, "4. RUH (Rapport om uønsket hendelse)", 4);
|
||||
addFormButton(formsContainer, "9. Sikkerhetskurs / Kompetansebevis", 9);
|
||||
addFormButton(formsContainer, "10. HMS-bekreftelse", 10);
|
||||
addFormButton(formsContainer, "11. Egenmelding", 11);
|
||||
addFormButton(formsContainer, "12. Sjekkliste for firmabil", 12);
|
||||
addFormButton(formsContainer, "14. SJA (Sikker Jobbanalyse)", 14);
|
||||
addFormButton(formsContainer, "15. Fraværsvarsel", 15);
|
||||
addFormButton(formsContainer, "16. Refusjon utlegg", 16);
|
||||
addFormButton(formsContainer, "21. Forberedelse til medarbeidersamtale", 21);
|
||||
addFormButton(formsContainer, "22. Medarbeiderundersøkelse", 22);
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
fetchFormsList();
|
||||
}
|
||||
|
||||
private void fetchFormsList() {
|
||||
if (container != null) container.removeAllViews();
|
||||
if (loadingSpinner != null) loadingSpinner.setVisibility(View.VISIBLE);
|
||||
if (txtStatus != null) txtStatus.setText("");
|
||||
|
||||
// Vi bruker standard-kallet som er raskt og effektivt
|
||||
RetrofitClient.getApiService().getFormsListMap().enqueue(new Callback<Map<String, GravityForm>>() {
|
||||
@Override
|
||||
public void onResponse(Call<Map<String, GravityForm>> call, Response<Map<String, GravityForm>> response) {
|
||||
if (getContext() == null) return;
|
||||
if (loadingSpinner != null) loadingSpinner.setVisibility(View.GONE);
|
||||
|
||||
if (response.isSuccessful() && response.body() != null) {
|
||||
Map<String, GravityForm> formMap = response.body();
|
||||
|
||||
if (formMap.isEmpty()) {
|
||||
if (txtStatus != null) txtStatus.setText("Ingen skjemaer funnet.");
|
||||
return;
|
||||
}
|
||||
|
||||
List<GravityForm> visibleForms = new ArrayList<>();
|
||||
for (GravityForm form : formMap.values()) {
|
||||
// Sjekk om aktiv
|
||||
boolean isActive = form.isActive == null || !"0".equals(form.isActive);
|
||||
|
||||
// Sjekk om vi finner et sorteringstall i tittelen
|
||||
Integer sortOrder = getSortOrderFromTitle(form.title);
|
||||
|
||||
if (form != null && form.title != null && isActive && sortOrder != null) {
|
||||
visibleForms.add(form);
|
||||
}
|
||||
}
|
||||
|
||||
if (visibleForms.isEmpty()) {
|
||||
if (txtStatus != null) txtStatus.setText("Ingen tilgjengelige skjemaer (sjekk nummerering i titler).");
|
||||
return;
|
||||
}
|
||||
|
||||
// Sorter listen basert på tallet i tittelen
|
||||
Collections.sort(visibleForms, new Comparator<GravityForm>() {
|
||||
@Override
|
||||
public int compare(GravityForm f1, GravityForm f2) {
|
||||
return Integer.compare(getSortOrderFromTitle(f1.title), getSortOrderFromTitle(f2.title));
|
||||
}
|
||||
});
|
||||
|
||||
for (GravityForm form : visibleForms) {
|
||||
addFormButton(form);
|
||||
}
|
||||
|
||||
} else {
|
||||
if (txtStatus != null) txtStatus.setText("Kunne ikke laste listen (Kode " + response.code() + ")");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Call<Map<String, GravityForm>> call, Throwable t) {
|
||||
if (getContext() == null) return;
|
||||
if (loadingSpinner != null) loadingSpinner.setVisibility(View.GONE);
|
||||
if (txtStatus != null) txtStatus.setText("Nettverksfeil: " + t.getMessage());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Henter ut tallet fra starten av tittelen.
|
||||
* Returnerer null hvis tittelen ikke starter med et tall.
|
||||
*/
|
||||
private Integer getSortOrderFromTitle(String title) {
|
||||
if (title == null) return null;
|
||||
Matcher m = TITLE_PATTERN.matcher(title.trim());
|
||||
if (m.find()) {
|
||||
try {
|
||||
return Integer.parseInt(m.group(1));
|
||||
} catch (NumberFormatException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return null; // Ingen tall funnet -> Skjules
|
||||
}
|
||||
|
||||
/**
|
||||
* Henter ut selve navnet på skjemaet (uten tallet foran).
|
||||
* "10. Ansatte" -> "Ansatte"
|
||||
*/
|
||||
private String getCleanTitle(String title) {
|
||||
if (title == null) return "";
|
||||
Matcher m = TITLE_PATTERN.matcher(title.trim());
|
||||
if (m.find()) {
|
||||
// Group 2 er resten av teksten etter tallet og punktum/mellomrom
|
||||
return m.group(2);
|
||||
}
|
||||
return title; // Fallback hvis regex ikke matcher (skal ikke skje pga filtreringen over)
|
||||
}
|
||||
|
||||
private void addFormButton(GravityForm form) {
|
||||
Button button = new Button(getContext());
|
||||
|
||||
// VIS VASKET TITTEL PÅ KNAPPEN
|
||||
String displayTitle = getCleanTitle(form.title);
|
||||
button.setText(displayTitle.toUpperCase());
|
||||
|
||||
button.setTextColor(Color.WHITE);
|
||||
button.setBackgroundColor(Color.parseColor("#0069B3")); // KBS Blå
|
||||
button.setTextSize(14);
|
||||
button.setPadding(30, 30, 30, 30);
|
||||
|
||||
button.setOnClickListener(v -> {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putInt("formId", form.id);
|
||||
Navigation.findNavController(v).navigate(R.id.action_formsListFragment_to_formsDetailFragment, bundle);
|
||||
});
|
||||
private void addFormButton(LinearLayout container, String title, int formId) {
|
||||
Button btn = new Button(getContext());
|
||||
btn.setText(title);
|
||||
btn.setBackgroundColor(Color.parseColor("#0069B3")); // KBS Blå
|
||||
btn.setTextColor(Color.WHITE);
|
||||
btn.setPadding(30, 30, 30, 30);
|
||||
|
||||
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
);
|
||||
params.setMargins(0, 0, 0, 20);
|
||||
button.setLayoutParams(params);
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
params.setMargins(0, 0, 0, 20); // Litt avstand mellom knappene
|
||||
btn.setLayoutParams(params);
|
||||
|
||||
container.addView(button);
|
||||
btn.setOnClickListener(v -> {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putInt("formId", formId);
|
||||
Navigation.findNavController(v).navigate(R.id.nav_forms, bundle);
|
||||
});
|
||||
|
||||
container.addView(btn);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3212,79 +3314,130 @@ FILSTI: app\src\main\res\layout\activity_main.xml
|
|||
FILSTI: app\src\main\res\layout\fragment_forms.xml
|
||||
============================================================
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<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:padding="16dp"
|
||||
android:background="@android:color/white">
|
||||
android:orientation="vertical"
|
||||
android:background="#F5F5F5"
|
||||
tools:context=".FormsFragment">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/main_layout"
|
||||
android:id="@+id/history_wrapper"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Skjema"
|
||||
android:textSize="24sp"
|
||||
android:textStyle="bold"
|
||||
android:layout_marginBottom="16dp"/>
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/loading_spinner"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:visibility="visible" />
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="3"
|
||||
android:orientation="vertical"
|
||||
android:background="#FFFFFF"
|
||||
android:elevation="4dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:padding="16dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/lbl_history"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Tidligere innsendinger:"
|
||||
android:text="Tidligere innsendinger"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_marginBottom="5dp"/>
|
||||
android:textColor="#333333"
|
||||
android:layout_marginBottom="10dp"/>
|
||||
|
||||
<ScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/historyContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:layout_marginBottom="20dp"/>
|
||||
android:orientation="vertical" />
|
||||
</ScrollView>
|
||||
</LinearLayout>
|
||||
|
||||
<View
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="2dp"
|
||||
android:background="#0069B3"
|
||||
android:layout_marginBottom="20dp"/>
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="7"
|
||||
android:orientation="vertical"
|
||||
android:background="#FFFFFF"
|
||||
android:elevation="4dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical"
|
||||
android:padding="8dp"
|
||||
android:background="#FAFAFA">
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/loading_spinner"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:visibility="gone"
|
||||
android:layout_marginEnd="8dp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/txt_status"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Ny innsending:"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold"
|
||||
android:layout_marginBottom="10dp"/>
|
||||
android:textColor="#666666"
|
||||
android:textSize="12sp" />
|
||||
</LinearLayout>
|
||||
|
||||
<ScrollView
|
||||
android:id="@+id/form_scroll_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:padding="16dp"
|
||||
android:fillViewport="true">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/form_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical" />
|
||||
android:orientation="vertical"
|
||||
android:paddingBottom="40dp">
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
============================================================
|
||||
FILSTI: app\src\main\res\layout\fragment_forms_list.xml
|
||||
============================================================
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/main_layout" android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp"
|
||||
android:background="#F5F5F5">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/txt_status"
|
||||
android:id="@+id/header_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Skjemaer"
|
||||
android:textSize="24sp"
|
||||
android:textStyle="bold"
|
||||
android:layout_marginBottom="20dp"
|
||||
android:textColor="#333333"/>
|
||||
|
||||
<ScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/forms_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="10dp"
|
||||
android:textColor="#D32F2F"
|
||||
android:gravity="center" />
|
||||
android:orientation="vertical" />
|
||||
</ScrollView>
|
||||
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
</LinearLayout>
|
||||
|
||||
============================================================
|
||||
FILSTI: app\src\main\res\layout\fragment_handbook.xml
|
||||
|
|
@ -3836,6 +3989,14 @@ FILSTI: app\src\main\res\xml\data_extraction_rules.xml
|
|||
-->
|
||||
</data-extraction-rules>
|
||||
|
||||
============================================================
|
||||
FILSTI: app\src\main\res\xml\file_paths.xml
|
||||
============================================================
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<paths>
|
||||
<external-files-path name="my_images" path="Pictures" />
|
||||
</paths>
|
||||
|
||||
============================================================
|
||||
FILSTI: app\src\test\java\com\kbs\kbsintranett\ExampleUnitTest.java
|
||||
============================================================
|
||||
|
|
|
|||
Loading…
Reference in a new issue