Opprette kalender og varsler fungerer. Dette er før utvidelse
This commit is contained in:
parent
544cda4ce4
commit
fb9749ba3f
15 changed files with 917 additions and 73 deletions
|
|
@ -118,11 +118,7 @@ public class CalendarManager {
|
|||
}
|
||||
|
||||
CalendarEvent event = new CalendarEvent(title, rawStart, rawEnd, desc, loc);
|
||||
|
||||
// For lokale events bruker vi ikke reminderMinutes fra API,
|
||||
// men systemet håndterer varsling selv for lokale kalendere.
|
||||
// Vi setter den til 0 her for å unngå doble varsler fra appen.
|
||||
event.setReminderMinutes(0);
|
||||
event.setReminderMinutes(0); // Systemet håndterer lokale varsler
|
||||
|
||||
formatEventForUI(event);
|
||||
deviceEvents.add(event);
|
||||
|
|
|
|||
426
app/src/main/java/com/kbs/kbsintranett/CreateEventFragment.java
Normal file
426
app/src/main/java/com/kbs/kbsintranett/CreateEventFragment.java
Normal file
|
|
@ -0,0 +1,426 @@
|
|||
package com.kbs.kbsintranett;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.app.DatePickerDialog;
|
||||
import android.app.TimePickerDialog;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.RadioGroup;
|
||||
import android.widget.Spinner;
|
||||
import android.widget.Switch;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
import android.widget.ToggleButton;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.navigation.Navigation;
|
||||
import com.google.gson.JsonElement;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import retrofit2.Call;
|
||||
import retrofit2.Callback;
|
||||
import retrofit2.Response;
|
||||
|
||||
public class CreateEventFragment extends Fragment {
|
||||
private EditText etTitle, etDesc, etLocation;
|
||||
private Spinner spinnerCalendar, spinnerReminder, spinnerRecurrence;
|
||||
private Switch switchAllDay;
|
||||
private TextView txtPreview;
|
||||
private Button btnStartDate, btnStartTime, btnEndDate, btnEndTime, btnSave;
|
||||
|
||||
private Calendar startCal = Calendar.getInstance();
|
||||
private Calendar endCal = Calendar.getInstance();
|
||||
|
||||
private String selectedRRule = null;
|
||||
private boolean isCustomRecurrence = false;
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
return inflater.inflate(R.layout.fragment_create_event, container, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
|
||||
etTitle = view.findViewById(R.id.et_title);
|
||||
etDesc = view.findViewById(R.id.et_desc);
|
||||
etLocation = view.findViewById(R.id.et_location);
|
||||
switchAllDay = view.findViewById(R.id.switch_all_day);
|
||||
|
||||
spinnerCalendar = view.findViewById(R.id.spinner_calendar);
|
||||
spinnerReminder = view.findViewById(R.id.spinner_reminder);
|
||||
spinnerRecurrence = view.findViewById(R.id.spinner_recurrence);
|
||||
|
||||
txtPreview = view.findViewById(R.id.txt_time_preview);
|
||||
|
||||
btnStartDate = view.findViewById(R.id.btn_start_date);
|
||||
btnStartTime = view.findViewById(R.id.btn_start_time);
|
||||
btnEndDate = view.findViewById(R.id.btn_end_date);
|
||||
btnEndTime = view.findViewById(R.id.btn_end_time);
|
||||
|
||||
btnSave = view.findViewById(R.id.btn_save_event);
|
||||
|
||||
// Initialiser tid (neste hele time)
|
||||
startCal.add(Calendar.HOUR_OF_DAY, 1);
|
||||
startCal.set(Calendar.MINUTE, 0);
|
||||
endCal.setTime(startCal.getTime());
|
||||
endCal.add(Calendar.HOUR_OF_DAY, 1);
|
||||
|
||||
setupStandardSpinners();
|
||||
updateRecurrenceSpinner();
|
||||
updateUI();
|
||||
|
||||
// Listeners
|
||||
switchAllDay.setOnCheckedChangeListener((btn, isChecked) -> updateUI());
|
||||
|
||||
btnStartDate.setOnClickListener(v -> pickDate(startCal, true));
|
||||
btnEndDate.setOnClickListener(v -> pickDate(endCal, false));
|
||||
|
||||
btnStartTime.setOnClickListener(v -> pickTime(startCal));
|
||||
btnEndTime.setOnClickListener(v -> pickTime(endCal));
|
||||
|
||||
btnSave.setOnClickListener(v -> submitEvent());
|
||||
|
||||
spinnerRecurrence.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
|
||||
@Override
|
||||
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
|
||||
String selected = parent.getItemAtPosition(position).toString();
|
||||
|
||||
if (selected.equals("Egendefinert...")) {
|
||||
showCustomRecurrenceDialog();
|
||||
} else if (selected.startsWith("Ikke gjenta")) {
|
||||
selectedRRule = null;
|
||||
} else {
|
||||
generateStandardRRule(position);
|
||||
}
|
||||
}
|
||||
@Override public void onNothingSelected(AdapterView<?> parent) {}
|
||||
});
|
||||
}
|
||||
|
||||
private void setupStandardSpinners() {
|
||||
// Må matche PHP switch-case nøyaktig
|
||||
String[] calendars = {
|
||||
"Felles",
|
||||
"Administrasjonen",
|
||||
"Serviceavdelingen",
|
||||
"Automasjonsavdelingen",
|
||||
"Prosjektavdelingen"
|
||||
};
|
||||
spinnerCalendar.setAdapter(new ArrayAdapter<>(getContext(), android.R.layout.simple_spinner_dropdown_item, calendars));
|
||||
|
||||
String[] reminders = {"Ingen varsling", "10 min før", "15 min før", "30 min før", "1 time før", "2 timer før", "24 timer før"};
|
||||
ArrayAdapter<String> remAdapter = new ArrayAdapter<>(getContext(), android.R.layout.simple_spinner_dropdown_item, reminders);
|
||||
spinnerReminder.setAdapter(remAdapter);
|
||||
spinnerReminder.setSelection(2); // 15 min default
|
||||
}
|
||||
|
||||
private void updateRecurrenceSpinner() {
|
||||
String dayName = new SimpleDateFormat("EEEE", new Locale("no")).format(startCal.getTime());
|
||||
int dayOfMonth = startCal.get(Calendar.DAY_OF_MONTH);
|
||||
String monthName = new SimpleDateFormat("MMMM", new Locale("no")).format(startCal.getTime());
|
||||
|
||||
int weekNo = (startCal.get(Calendar.DAY_OF_MONTH) - 1) / 7 + 1;
|
||||
String nthDayString = "månedlig den " + weekNo + ". " + dayName + "en";
|
||||
|
||||
List<String> options = new ArrayList<>();
|
||||
options.add("Ikke gjenta");
|
||||
options.add("Daglig");
|
||||
options.add("Ukentlig på " + dayName);
|
||||
options.add("Månedlig den " + dayOfMonth + ".");
|
||||
options.add(capitalize(nthDayString));
|
||||
options.add("Årlig den " + dayOfMonth + ". " + monthName);
|
||||
options.add("Hver ukedag (man-fre)");
|
||||
options.add("Egendefinert...");
|
||||
|
||||
ArrayAdapter<String> adapter = new ArrayAdapter<>(getContext(), android.R.layout.simple_spinner_dropdown_item, options);
|
||||
spinnerRecurrence.setAdapter(adapter);
|
||||
}
|
||||
|
||||
private void generateStandardRRule(int position) {
|
||||
switch (position) {
|
||||
case 1: selectedRRule = "RRULE:FREQ=DAILY"; break;
|
||||
case 2: selectedRRule = "RRULE:FREQ=WEEKLY"; break;
|
||||
case 3: selectedRRule = "RRULE:FREQ=MONTHLY"; break;
|
||||
case 4:
|
||||
int weekNo = (startCal.get(Calendar.DAY_OF_MONTH) - 1) / 7 + 1;
|
||||
String dayCode = getDayCode(startCal.get(Calendar.DAY_OF_WEEK));
|
||||
selectedRRule = "RRULE:FREQ=MONTHLY;BYDAY=" + weekNo + dayCode;
|
||||
break;
|
||||
case 5: selectedRRule = "RRULE:FREQ=YEARLY"; break;
|
||||
case 6: selectedRRule = "RRULE:FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR"; break;
|
||||
default: selectedRRule = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void showCustomRecurrenceDialog() {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
|
||||
View view = LayoutInflater.from(getContext()).inflate(R.layout.dialog_custom_recurrence, null);
|
||||
|
||||
EditText etInterval = view.findViewById(R.id.et_interval);
|
||||
Spinner spinnerFreq = view.findViewById(R.id.spinner_freq);
|
||||
View layoutWeekdays = view.findViewById(R.id.layout_weekdays);
|
||||
|
||||
ToggleButton[] toggles = {
|
||||
view.findViewById(R.id.tg_mon), view.findViewById(R.id.tg_tue),
|
||||
view.findViewById(R.id.tg_wed), view.findViewById(R.id.tg_thu),
|
||||
view.findViewById(R.id.tg_fri), view.findViewById(R.id.tg_sat),
|
||||
view.findViewById(R.id.tg_sun)
|
||||
};
|
||||
String[] labels = {"M", "T", "O", "T", "F", "L", "S"};
|
||||
for(int i=0; i<7; i++) { toggles[i].setText(labels[i]); toggles[i].setTextOn(labels[i]); toggles[i].setTextOff(labels[i]); }
|
||||
|
||||
RadioGroup rgEnd = view.findViewById(R.id.rg_end);
|
||||
Button btnEndDatePicker = view.findViewById(R.id.btn_end_date_picker);
|
||||
EditText etCount = view.findViewById(R.id.et_count);
|
||||
Calendar customEndCal = Calendar.getInstance();
|
||||
customEndCal.add(Calendar.MONTH, 1);
|
||||
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("d. MMM yyyy", Locale.getDefault());
|
||||
btnEndDatePicker.setText(sdf.format(customEndCal.getTime()));
|
||||
|
||||
btnEndDatePicker.setOnClickListener(v -> {
|
||||
rgEnd.check(R.id.rb_date);
|
||||
new DatePickerDialog(getContext(), (p, y, m, d) -> {
|
||||
customEndCal.set(y, m, d);
|
||||
btnEndDatePicker.setText(sdf.format(customEndCal.getTime()));
|
||||
}, customEndCal.get(Calendar.YEAR), customEndCal.get(Calendar.MONTH), customEndCal.get(Calendar.DAY_OF_MONTH)).show();
|
||||
});
|
||||
|
||||
spinnerFreq.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
|
||||
@Override
|
||||
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
|
||||
layoutWeekdays.setVisibility(position == 1 ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
@Override public void onNothingSelected(AdapterView<?> parent) {}
|
||||
});
|
||||
|
||||
builder.setView(view);
|
||||
AlertDialog dialog = builder.create();
|
||||
|
||||
view.findViewById(R.id.btn_cancel).setOnClickListener(v -> {
|
||||
dialog.dismiss();
|
||||
spinnerRecurrence.setSelection(0);
|
||||
});
|
||||
|
||||
view.findViewById(R.id.btn_done).setOnClickListener(v -> {
|
||||
StringBuilder rrule = new StringBuilder("RRULE:");
|
||||
int freqPos = spinnerFreq.getSelectedItemPosition();
|
||||
String freq = "";
|
||||
switch (freqPos) {
|
||||
case 0: freq = "DAILY"; break;
|
||||
case 1: freq = "WEEKLY"; break;
|
||||
case 2: freq = "MONTHLY"; break;
|
||||
case 3: freq = "YEARLY"; break;
|
||||
}
|
||||
rrule.append("FREQ=").append(freq);
|
||||
|
||||
String interval = etInterval.getText().toString();
|
||||
if (!interval.isEmpty() && !interval.equals("1")) {
|
||||
rrule.append(";INTERVAL=").append(interval);
|
||||
}
|
||||
|
||||
if (freq.equals("WEEKLY")) {
|
||||
List<String> days = new ArrayList<>();
|
||||
String[] codes = {"MO", "TU", "WE", "TH", "FR", "SA", "SU"};
|
||||
for (int i=0; i<7; i++) {
|
||||
if (toggles[i].isChecked()) days.add(codes[i]);
|
||||
}
|
||||
if (!days.isEmpty()) {
|
||||
rrule.append(";BYDAY=").append(String.join(",", days));
|
||||
}
|
||||
}
|
||||
|
||||
int checkedId = rgEnd.getCheckedRadioButtonId();
|
||||
if (checkedId == R.id.rb_date) {
|
||||
customEndCal.set(Calendar.HOUR_OF_DAY, 23);
|
||||
customEndCal.set(Calendar.MINUTE, 59);
|
||||
customEndCal.setTimeZone(java.util.TimeZone.getTimeZone("UTC"));
|
||||
SimpleDateFormat utc = new SimpleDateFormat("yyyyMMdd'T'HHmmss'Z'", Locale.US);
|
||||
utc.setTimeZone(java.util.TimeZone.getTimeZone("UTC"));
|
||||
rrule.append(";UNTIL=").append(utc.format(customEndCal.getTime()));
|
||||
} else if (checkedId == R.id.rb_count) {
|
||||
rrule.append(";COUNT=").append(etCount.getText().toString());
|
||||
}
|
||||
|
||||
selectedRRule = rrule.toString();
|
||||
isCustomRecurrence = true;
|
||||
dialog.dismiss();
|
||||
});
|
||||
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
private void pickDate(Calendar cal, boolean isStart) {
|
||||
new DatePickerDialog(getContext(), (view, y, m, d) -> {
|
||||
cal.set(y, m, d);
|
||||
if (isStart) {
|
||||
if (endCal.before(startCal)) {
|
||||
endCal.setTime(startCal.getTime());
|
||||
if (!switchAllDay.isChecked()) endCal.add(Calendar.HOUR_OF_DAY, 1);
|
||||
}
|
||||
updateRecurrenceSpinner();
|
||||
if (!isCustomRecurrence) spinnerRecurrence.setSelection(0);
|
||||
}
|
||||
updateUI();
|
||||
}, cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH)).show();
|
||||
}
|
||||
|
||||
private void pickTime(Calendar cal) {
|
||||
new TimePickerDialog(getContext(), (view, h, m) -> {
|
||||
cal.set(Calendar.HOUR_OF_DAY, h);
|
||||
cal.set(Calendar.MINUTE, m);
|
||||
if (cal == startCal && endCal.before(startCal)) {
|
||||
endCal.setTime(startCal.getTime());
|
||||
endCal.add(Calendar.HOUR_OF_DAY, 1);
|
||||
}
|
||||
updateUI();
|
||||
}, cal.get(Calendar.HOUR_OF_DAY), cal.get(Calendar.MINUTE), true).show();
|
||||
}
|
||||
|
||||
private void updateUI() {
|
||||
boolean isAllDay = switchAllDay.isChecked();
|
||||
|
||||
btnStartTime.setVisibility(isAllDay ? View.GONE : View.VISIBLE);
|
||||
btnEndTime.setVisibility(isAllDay ? View.GONE : View.VISIBLE);
|
||||
|
||||
SimpleDateFormat dateFmt = new SimpleDateFormat("dd.MM.yyyy", Locale.getDefault());
|
||||
SimpleDateFormat timeFmt = new SimpleDateFormat("HH:mm", Locale.getDefault());
|
||||
|
||||
btnStartDate.setText(dateFmt.format(startCal.getTime()));
|
||||
btnEndDate.setText(dateFmt.format(endCal.getTime()));
|
||||
btnStartTime.setText(timeFmt.format(startCal.getTime()));
|
||||
btnEndTime.setText(timeFmt.format(endCal.getTime()));
|
||||
|
||||
String preview = dateFmt.format(startCal.getTime());
|
||||
if (!isAllDay) preview += " " + timeFmt.format(startCal.getTime());
|
||||
preview += " - ";
|
||||
|
||||
if (isSameDay(startCal, endCal)) {
|
||||
if (isAllDay) preview += " (Samme dag)";
|
||||
else preview += timeFmt.format(endCal.getTime());
|
||||
} else {
|
||||
preview += dateFmt.format(endCal.getTime());
|
||||
if (!isAllDay) preview += " " + timeFmt.format(endCal.getTime());
|
||||
}
|
||||
txtPreview.setText(preview);
|
||||
}
|
||||
|
||||
private boolean isSameDay(Calendar c1, Calendar c2) {
|
||||
return c1.get(Calendar.YEAR) == c2.get(Calendar.YEAR) &&
|
||||
c1.get(Calendar.DAY_OF_YEAR) == c2.get(Calendar.DAY_OF_YEAR);
|
||||
}
|
||||
|
||||
private String capitalize(String s) {
|
||||
if (s == null || s.isEmpty()) return s;
|
||||
return s.substring(0, 1).toUpperCase() + s.substring(1);
|
||||
}
|
||||
|
||||
private String getDayCode(int calendarDay) {
|
||||
switch (calendarDay) {
|
||||
case Calendar.MONDAY: return "MO";
|
||||
case Calendar.TUESDAY: return "TU";
|
||||
case Calendar.WEDNESDAY: return "WE";
|
||||
case Calendar.THURSDAY: return "TH";
|
||||
case Calendar.FRIDAY: return "FR";
|
||||
case Calendar.SATURDAY: return "SA";
|
||||
case Calendar.SUNDAY: return "SU";
|
||||
default: return "MO";
|
||||
}
|
||||
}
|
||||
|
||||
private String getCalendarSlug() {
|
||||
int pos = spinnerCalendar.getSelectedItemPosition();
|
||||
switch (pos) {
|
||||
case 1: return "Administrasjonen";
|
||||
case 2: return "Serviceavdelingen";
|
||||
case 3: return "Automasjonsavdelingen";
|
||||
case 4: return "Prosjektavdelingen";
|
||||
default: return "Felles"; // case 0
|
||||
}
|
||||
}
|
||||
|
||||
private int getReminderMinutes() {
|
||||
int pos = spinnerReminder.getSelectedItemPosition();
|
||||
switch (pos) {
|
||||
case 1: return 10;
|
||||
case 2: return 15;
|
||||
case 3: return 30;
|
||||
case 4: return 60;
|
||||
case 5: return 120;
|
||||
case 6: return 1440;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private void submitEvent() {
|
||||
String title = etTitle.getText().toString().trim();
|
||||
if (title.isEmpty()) {
|
||||
etTitle.setError("Mangler tittel");
|
||||
return;
|
||||
}
|
||||
|
||||
boolean isAllDay = switchAllDay.isChecked();
|
||||
String format = isAllDay ? "yyyy-MM-dd" : "yyyy-MM-dd'T'HH:mm";
|
||||
SimpleDateFormat sdf = new SimpleDateFormat(format, Locale.getDefault());
|
||||
|
||||
CreateEventRequest req = new CreateEventRequest(
|
||||
title,
|
||||
etDesc.getText().toString(),
|
||||
etLocation.getText().toString(),
|
||||
sdf.format(startCal.getTime()),
|
||||
sdf.format(endCal.getTime()),
|
||||
getCalendarSlug(),
|
||||
getReminderMinutes(),
|
||||
isAllDay,
|
||||
selectedRRule
|
||||
);
|
||||
|
||||
Toast.makeText(getContext(), "Oppretter...", Toast.LENGTH_SHORT).show();
|
||||
|
||||
// HER ER DEN NYE LOGIKKEN FOR Å LESE FEILMELDING FRA PHP
|
||||
RetrofitClient.getApiService().createCalendarEvent(req).enqueue(new Callback<JsonElement>() {
|
||||
@Override
|
||||
public void onResponse(Call<JsonElement> call, Response<JsonElement> response) {
|
||||
if (response.isSuccessful()) {
|
||||
Toast.makeText(getContext(), "Hendelse opprettet!", Toast.LENGTH_LONG).show();
|
||||
Navigation.findNavController(getView()).navigateUp();
|
||||
} else {
|
||||
// Les feilmelding fra serveren (body)
|
||||
String errorMsg = "Ukjent feil";
|
||||
try {
|
||||
if (response.errorBody() != null) {
|
||||
errorMsg = response.errorBody().string();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
errorMsg = "Kunne ikke lese feil: " + e.getMessage();
|
||||
}
|
||||
|
||||
Log.e("KBS_ERROR", "Server svarte med feil: " + errorMsg);
|
||||
// Vis en kortversjon til brukeren, eller hele hvis du debugger
|
||||
Toast.makeText(getContext(), "Feil (" + response.code() + "): Sjekk Logcat", Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Call<JsonElement> call, Throwable t) {
|
||||
Log.e("KBS_ERROR", "Nettverksfeil", t);
|
||||
Toast.makeText(getContext(), "Nettverksfeil: " + t.getMessage(), Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,4 +1,43 @@
|
|||
package com.kbs.kbsintranett;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
public class CreateEventRequest {
|
||||
@SerializedName("title")
|
||||
public String title;
|
||||
|
||||
@SerializedName("description")
|
||||
public String description;
|
||||
|
||||
@SerializedName("location")
|
||||
public String location; // NY
|
||||
|
||||
@SerializedName("start_time")
|
||||
public String startTime;
|
||||
|
||||
@SerializedName("end_time")
|
||||
public String endTime;
|
||||
|
||||
@SerializedName("calendar_type")
|
||||
public String calendarType;
|
||||
|
||||
@SerializedName("reminder_minutes")
|
||||
public int reminderMinutes;
|
||||
|
||||
@SerializedName("is_all_day")
|
||||
public boolean isAllDay; // NY
|
||||
|
||||
@SerializedName("recurrence")
|
||||
public String recurrence; // NY (RRULE)
|
||||
|
||||
public CreateEventRequest(String title, String description, String location, String startTime, String endTime, String calendarType, int reminderMinutes, boolean isAllDay, String recurrence) {
|
||||
this.title = title;
|
||||
this.description = description;
|
||||
this.location = location;
|
||||
this.startTime = startTime;
|
||||
this.endTime = endTime;
|
||||
this.calendarType = calendarType;
|
||||
this.reminderMinutes = reminderMinutes;
|
||||
this.isAllDay = isAllDay;
|
||||
this.recurrence = recurrence;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,10 +3,13 @@ package com.kbs.kbsintranett;
|
|||
import android.Manifest;
|
||||
import android.content.pm.PackageManager;
|
||||
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.TextView;
|
||||
import android.widget.Toast;
|
||||
import androidx.activity.result.ActivityResultLauncher;
|
||||
import androidx.activity.result.contract.ActivityResultContracts;
|
||||
import androidx.annotation.NonNull;
|
||||
|
|
@ -30,7 +33,6 @@ import retrofit2.Callback;
|
|||
import retrofit2.Response;
|
||||
|
||||
public class HomeFragment extends Fragment {
|
||||
|
||||
private ActivityResultLauncher<String> requestPermissionLauncher;
|
||||
private RecyclerView calendarRecycler;
|
||||
|
||||
|
|
@ -63,6 +65,16 @@ public class HomeFragment extends Fragment {
|
|||
profileBtn.setOnClickListener(v -> Navigation.findNavController(view).navigate(R.id.navigation_profile));
|
||||
}
|
||||
|
||||
Button btnCreateEvent = view.findViewById(R.id.btn_create_event);
|
||||
if (UserManager.getInstance().isEditorOrAbove()) {
|
||||
btnCreateEvent.setVisibility(View.VISIBLE);
|
||||
btnCreateEvent.setOnClickListener(v -> {
|
||||
Navigation.findNavController(view).navigate(R.id.action_home_to_create_event);
|
||||
});
|
||||
} else {
|
||||
btnCreateEvent.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
calendarRecycler = view.findViewById(R.id.recycler_calendar);
|
||||
calendarRecycler.setLayoutManager(new LinearLayoutManager(getContext()));
|
||||
calendarRecycler.setAdapter(new CalendarAdapter(new ArrayList<>(), event -> {}));
|
||||
|
|
@ -100,10 +112,8 @@ public class HomeFragment extends Fragment {
|
|||
}
|
||||
|
||||
private void fetchCalendarEvents(RecyclerView recyclerView) {
|
||||
// 1. Hent personlige hendelser
|
||||
List<CalendarEvent> deviceEvents = CalendarManager.getDeviceEvents(getContext());
|
||||
|
||||
// 2. Hent felles hendelser fra WordPress (Proxy mot Google)
|
||||
RetrofitClient.getApiService().getCalendarEvents().enqueue(new Callback<List<CalendarEvent>>() {
|
||||
@Override
|
||||
public void onResponse(Call<List<CalendarEvent>> call, Response<List<CalendarEvent>> response) {
|
||||
|
|
@ -112,16 +122,12 @@ public class HomeFragment extends Fragment {
|
|||
List<CalendarEvent> apiEvents = new ArrayList<>();
|
||||
if (response.isSuccessful() && response.body() != null) {
|
||||
apiEvents = response.body();
|
||||
// Formater datoer for visning (UI-logikk)
|
||||
for (CalendarEvent e : apiEvents) {
|
||||
CalendarManager.formatEventForUI(e);
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Flett og sorter
|
||||
List<CalendarEvent> merged = CalendarManager.mergeAndSort(apiEvents, deviceEvents);
|
||||
|
||||
// 4. Filtrer (kun fremtidige + i dag)
|
||||
List<CalendarEvent> upcomingEvents = new ArrayList<>();
|
||||
String today = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).format(new Date());
|
||||
|
||||
|
|
@ -131,7 +137,6 @@ public class HomeFragment extends Fragment {
|
|||
}
|
||||
}
|
||||
|
||||
// 5. Vis topp 5
|
||||
List<CalendarEvent> top5 = new ArrayList<>();
|
||||
for(int i=0; i<Math.min(upcomingEvents.size(), 5); i++) {
|
||||
top5.add(upcomingEvents.get(i));
|
||||
|
|
@ -146,7 +151,6 @@ public class HomeFragment extends Fragment {
|
|||
@Override
|
||||
public void onFailure(Call<List<CalendarEvent>> call, Throwable t) {
|
||||
if (!isAdded()) return;
|
||||
// Fallback til kun lokale events
|
||||
if (!deviceEvents.isEmpty()) {
|
||||
List<CalendarEvent> top5 = new ArrayList<>();
|
||||
for(int i=0; i<Math.min(deviceEvents.size(), 5); i++) top5.add(deviceEvents.get(i));
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ import java.util.Locale;
|
|||
import retrofit2.Response;
|
||||
|
||||
public class NotificationWorker extends Worker {
|
||||
private static final String TAG = "KBS_DEBUG";
|
||||
private static final String TAG = "NotificationWorker";
|
||||
|
||||
public NotificationWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) {
|
||||
super(context, workerParams);
|
||||
|
|
@ -26,26 +26,22 @@ public class NotificationWorker extends Worker {
|
|||
@NonNull
|
||||
@Override
|
||||
public Result doWork() {
|
||||
Log.d(TAG, "NotificationWorker: Starter sjekk av kalender via WordPress Proxy...");
|
||||
|
||||
try {
|
||||
Response<List<CalendarEvent>> response = RetrofitClient.getApiService().getCalendarEvents().execute();
|
||||
|
||||
if (response.isSuccessful() && response.body() != null) {
|
||||
List<CalendarEvent> events = response.body();
|
||||
scheduleAlarms(events);
|
||||
scheduleAlarms(response.body());
|
||||
return Result.success();
|
||||
} else {
|
||||
int code = response.code();
|
||||
Log.e(TAG, "NotificationWorker: API-kall mot WP feilet. Kode: " + code);
|
||||
// Stopp retry ved klientfeil (4xx) inkludert 429
|
||||
if (code >= 400 && code < 500) {
|
||||
// Ved klientfeil (4xx), stopp retry-loop
|
||||
if (response.code() >= 400 && response.code() < 500) {
|
||||
Log.w(TAG, "Kunne ikke hente kalender. Kode: " + response.code());
|
||||
return Result.failure();
|
||||
}
|
||||
return Result.retry();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "NotificationWorker: Nettverksfeil", e);
|
||||
Log.e(TAG, "Nettverksfeil under kalendersjekk", e);
|
||||
return Result.retry();
|
||||
}
|
||||
}
|
||||
|
|
@ -56,32 +52,23 @@ public class NotificationWorker extends Worker {
|
|||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
if (!alarmManager.canScheduleExactAlarms()) {
|
||||
Log.e(TAG, "NotificationWorker: MANGLER tillatelse for nøyaktige alarmer!");
|
||||
return;
|
||||
return; // Mangler rettigheter, kan ikke sette alarm
|
||||
}
|
||||
}
|
||||
|
||||
long now = System.currentTimeMillis();
|
||||
SimpleDateFormat isoFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.getDefault());
|
||||
|
||||
// Tillater alarmer som skulle gått for inntil 30 minutter siden (Catch-up)
|
||||
long catchUpWindow = now - (30 * 60 * 1000L);
|
||||
// Setter ikke alarmer lenger frem enn 24 timer
|
||||
long futureWindow = now + (24 * 60 * 60 * 1000L);
|
||||
|
||||
int countSet = 0;
|
||||
long catchUpWindow = now - (30 * 60 * 1000L); // 30 min bakover
|
||||
long futureWindow = now + (24 * 60 * 60 * 1000L); // 24 timer fremover
|
||||
|
||||
for (CalendarEvent event : events) {
|
||||
try {
|
||||
String title = event.getTitle();
|
||||
|
||||
// Ignorer heldagshendelser (datoformat uten klokkeslett)
|
||||
if (event.getRawDate() == null || event.getRawDate().length() == 10) continue;
|
||||
|
||||
Date eventDate = null;
|
||||
if (event.getRawDate().contains("T")) {
|
||||
String raw = event.getRawDate();
|
||||
// Kutter tidssone for å parse som lokal tid "face value"
|
||||
if (raw.length() > 19) raw = raw.substring(0, 19);
|
||||
eventDate = isoFormat.parse(raw);
|
||||
}
|
||||
|
|
@ -89,38 +76,22 @@ public class NotificationWorker extends Worker {
|
|||
if (eventDate == null) continue;
|
||||
|
||||
int minutesBefore = event.getReminderMinutes();
|
||||
long triggerTime = eventDate.getTime() - (minutesBefore * 60 * 1000L);
|
||||
|
||||
// --- DIAGNOSE: Logg alle "Test"-events for å se hva PHP faktisk leverer ---
|
||||
if (title.toLowerCase().contains("test")) {
|
||||
Log.d(TAG, "--------------------------------------------------");
|
||||
Log.d(TAG, "DIAGNOSE EVENT: " + title);
|
||||
Log.d(TAG, " Starttid: " + eventDate);
|
||||
Log.d(TAG, " PHP sier reminderMinutes: " + minutesBefore);
|
||||
|
||||
if (minutesBefore <= 0) {
|
||||
Log.d(TAG, " HANDLING: Skippes (Ingen varsling)");
|
||||
} else {
|
||||
Log.d(TAG, " Ønsket alarmtid: " + new Date(triggerTime));
|
||||
Log.d(TAG, " Nå: " + new Date(now));
|
||||
}
|
||||
}
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
if (minutesBefore <= 0) continue;
|
||||
|
||||
long triggerTime = eventDate.getTime() - (minutesBefore * 60 * 1000L);
|
||||
|
||||
// Sjekk om alarmen er innenfor tidsvinduet
|
||||
if (triggerTime > catchUpWindow && triggerTime < futureWindow) {
|
||||
|
||||
// CATCH-UP: Hvis tiden har passert, fyr av NÅ.
|
||||
// Catch-up: Hvis tiden har passert, fyr av umiddelbart
|
||||
if (triggerTime < now) {
|
||||
Log.i(TAG, " -> Alarmtid passert (" + new Date(triggerTime) + "). Kjører Catch-up NÅ.");
|
||||
triggerTime = now + 1000;
|
||||
}
|
||||
|
||||
int alarmId = (title + event.getRawDate()).hashCode();
|
||||
int alarmId = (event.getTitle() + event.getRawDate()).hashCode();
|
||||
|
||||
Intent intent = new Intent(context, AlarmReceiver.class);
|
||||
intent.putExtra("TITLE", title);
|
||||
intent.putExtra("TITLE", event.getTitle());
|
||||
String timeStr = new SimpleDateFormat("HH:mm", Locale.getDefault()).format(eventDate);
|
||||
intent.putExtra("MESSAGE", "Starter kl " + timeStr);
|
||||
intent.putExtra("ID", alarmId);
|
||||
|
|
@ -138,20 +109,13 @@ public class NotificationWorker extends Worker {
|
|||
alarmManager.setExact(AlarmManager.RTC_WAKEUP, triggerTime, pendingIntent);
|
||||
}
|
||||
|
||||
if (title.toLowerCase().contains("test")) {
|
||||
Log.d(TAG, " RESULTAT: ALARM SATT OK");
|
||||
Log.d(TAG, "--------------------------------------------------");
|
||||
}
|
||||
countSet++;
|
||||
// Logger kun når en alarm faktisk blir satt/oppdatert
|
||||
Log.i(TAG, "Alarm satt for: " + event.getTitle() + " (" + new Date(triggerTime) + ")");
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Feil ved behandling av event: " + event.getTitle(), e);
|
||||
Log.e(TAG, "Feil ved behandling av event", e);
|
||||
}
|
||||
}
|
||||
|
||||
if (countSet == 0) {
|
||||
Log.d(TAG, "Ingen nye alarmer satt i denne runden.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -18,15 +18,15 @@ import retrofit2.converter.gson.GsonConverterFactory;
|
|||
public class RetrofitClient {
|
||||
private static final String BASE_URL = "https://intranet.kbs.no/";
|
||||
private static Retrofit retrofit = null;
|
||||
|
||||
public static WordPressApiService getApiService() {
|
||||
if (retrofit == null) {
|
||||
|
||||
// ENDRET: Redusert loggnivå fra BODY til BASIC for å unngå spam i Logcat
|
||||
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
|
||||
if (BuildConfig.DEBUG) {
|
||||
// I debug-modus logger vi det mest nødvendige
|
||||
logging.setLevel(HttpLoggingInterceptor.Level.BASIC);
|
||||
} else {
|
||||
// I release er vi stille for ytelse og sikkerhet
|
||||
logging.setLevel(HttpLoggingInterceptor.Level.NONE);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ import retrofit2.http.Query;
|
|||
public interface WordPressApiService {
|
||||
@GET("wp-json/wp/v2/posts?per_page=10&_embed")
|
||||
Call<List<WpPost>> getPosts();
|
||||
|
||||
@GET("wp-json/kbs/v1/forms/{id}")
|
||||
Call<GravityForm> getForm(@Path("id") int formId);
|
||||
|
||||
|
|
@ -40,11 +39,13 @@ public interface WordPressApiService {
|
|||
@Part List<MultipartBody.Part> files
|
||||
);
|
||||
|
||||
// BRUKES NÅ: Henter kalenderhendelser via WordPress proxy.
|
||||
// Dette sikrer at vi får med reminder_minutes fra serveren.
|
||||
@GET("wp-json/kbs/v1/calendar/events")
|
||||
Call<List<CalendarEvent>> getCalendarEvents();
|
||||
|
||||
// DETTE ER METODEN SOM MANGLER:
|
||||
@POST("wp-json/kbs/v1/calendar/create")
|
||||
Call<JsonElement> createCalendarEvent(@Body CreateEventRequest request);
|
||||
|
||||
@GET("wp-json/gf/v2/entries")
|
||||
Call<GravityEntryResponse> getEntries(
|
||||
@Query("form_ids") int formId,
|
||||
|
|
|
|||
5
app/src/main/res/color/selector_day_text.xml
Normal file
5
app/src/main/res/color/selector_day_text.xml
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:state_checked="true" android:color="#FFFFFF"/>
|
||||
<item android:color="#333333"/>
|
||||
</selector>
|
||||
14
app/src/main/res/drawable/selector_day_toggle.xml
Normal file
14
app/src/main/res/drawable/selector_day_toggle.xml
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:state_checked="true">
|
||||
<shape android:shape="oval">
|
||||
<solid android:color="#0069B3"/> <!-- KBS Blå -->
|
||||
</shape>
|
||||
</item>
|
||||
<item>
|
||||
<shape android:shape="oval">
|
||||
<solid android:color="#EEEEEE"/> <!-- Lys grå -->
|
||||
</shape>
|
||||
</item>
|
||||
|
||||
</selector>
|
||||
177
app/src/main/res/layout/dialog_custom_recurrence.xml
Normal file
177
app/src/main/res/layout/dialog_custom_recurrence.xml
Normal file
|
|
@ -0,0 +1,177 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="24dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Egendefinert gjentakelse"
|
||||
android:textSize="20sp"
|
||||
android:textStyle="bold"
|
||||
android:textColor="#333"
|
||||
android:layout_marginBottom="24dp"/>
|
||||
|
||||
<!-- FREKVENS -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical"
|
||||
android:layout_marginBottom="24dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Gjenta hvert: "
|
||||
android:textSize="16sp"/>
|
||||
|
||||
<EditText
|
||||
android:id="@+id/et_interval"
|
||||
android:layout_width="60dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="number"
|
||||
android:text="1"
|
||||
android:gravity="center"
|
||||
android:layout_marginHorizontal="8dp"/>
|
||||
|
||||
<Spinner
|
||||
android:id="@+id/spinner_freq"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:entries="@array/recurrence_freq_array"/>
|
||||
</LinearLayout>
|
||||
|
||||
<!-- UKEDAGER (Vises kun hvis Uke er valgt) -->
|
||||
<LinearLayout
|
||||
android:id="@+id/layout_weekdays"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:layout_marginBottom="24dp"
|
||||
android:visibility="visible">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Gjenta på"
|
||||
android:layout_marginBottom="8dp"/>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:weightSum="7">
|
||||
|
||||
<ToggleButton android:id="@+id/tg_mon" android:textOn="M" android:textOff="M" style="@style/DayToggle"/>
|
||||
<ToggleButton android:id="@+id/tg_tue" android:textOn="T" android:textOff="T" style="@style/DayToggle"/>
|
||||
<ToggleButton android:id="@+id/tg_wed" android:textOn="O" android:textOff="O" style="@style/DayToggle"/>
|
||||
<ToggleButton android:id="@+id/tg_thu" android:textOn="T" android:textOff="T" style="@style/DayToggle"/>
|
||||
<ToggleButton android:id="@+id/tg_fri" android:textOn="F" android:textOff="F" style="@style/DayToggle"/>
|
||||
<ToggleButton android:id="@+id/tg_sat" android:textOn="L" android:textOff="L" style="@style/DayToggle"/>
|
||||
<ToggleButton android:id="@+id/tg_sun" android:textOn="S" android:textOff="S" style="@style/DayToggle"/>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<!-- SLUTTER -->
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Slutter"
|
||||
android:layout_marginBottom="8dp"/>
|
||||
|
||||
<RadioGroup
|
||||
android:id="@+id/rg_end"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/rb_never"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Aldri"
|
||||
android:checked="true"/>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical">
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/rb_date"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Den"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_end_date_picker"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Velg dato"
|
||||
android:layout_marginStart="16dp"
|
||||
style="@style/Widget.MaterialComponents.Button.TextButton"/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical">
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/rb_count"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Etter"/>
|
||||
|
||||
<EditText
|
||||
android:id="@+id/et_count"
|
||||
android:layout_width="60dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="number"
|
||||
android:text="13"
|
||||
android:gravity="center"
|
||||
android:layout_marginHorizontal="16dp"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="ganger"/>
|
||||
</LinearLayout>
|
||||
</RadioGroup>
|
||||
|
||||
<!-- KNAPPER -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="end"
|
||||
android:layout_marginTop="32dp">
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_cancel"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Avbryt"
|
||||
style="@style/Widget.MaterialComponents.Button.TextButton"
|
||||
android:textColor="#666"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_done"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Ferdig"
|
||||
android:backgroundTint="@color/kbs_logo_blue"
|
||||
android:textColor="#FFF"
|
||||
android:layout_marginStart="16dp"/>
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
170
app/src/main/res/layout/fragment_create_event.xml
Normal file
170
app/src/main/res/layout/fragment_create_event.xml
Normal file
|
|
@ -0,0 +1,170 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="#FFFFFF">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Opprett ny hendelse"
|
||||
android:textSize="24sp"
|
||||
android:textStyle="bold"
|
||||
android:layout_marginBottom="24dp"
|
||||
android:textColor="#333"/>
|
||||
|
||||
<EditText
|
||||
android:id="@+id/et_title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="Tittel"
|
||||
android:inputType="textCapSentences"
|
||||
android:padding="12dp"
|
||||
android:background="@android:drawable/edit_text"
|
||||
android:layout_marginBottom="16dp"/>
|
||||
|
||||
<EditText
|
||||
android:id="@+id/et_desc"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="Beskrivelse / Notater"
|
||||
android:inputType="textMultiLine"
|
||||
android:minLines="3"
|
||||
android:padding="12dp"
|
||||
android:gravity="top"
|
||||
android:background="@android:drawable/edit_text"
|
||||
android:layout_marginBottom="16dp"/>
|
||||
|
||||
<EditText
|
||||
android:id="@+id/et_location"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="Hvor (Sted)"
|
||||
android:inputType="textCapWords"
|
||||
android:padding="12dp"
|
||||
android:background="@android:drawable/edit_text"
|
||||
android:layout_marginBottom="16dp"/>
|
||||
|
||||
<Switch
|
||||
android:id="@+id/switch_all_day"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Hele dagen"
|
||||
android:layout_marginBottom="16dp"/>
|
||||
|
||||
<!-- Start Dato/Tid -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:layout_marginBottom="8dp">
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_start_date"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="Startdato"
|
||||
android:layout_marginEnd="4dp"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_start_time"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="Starttid"
|
||||
android:layout_marginStart="4dp"/>
|
||||
</LinearLayout>
|
||||
|
||||
<!-- Slutt Dato/Tid -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:layout_marginBottom="16dp">
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_end_date"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="Sluttdato"
|
||||
android:layout_marginEnd="4dp"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_end_time"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="Slutttid"
|
||||
android:layout_marginStart="4dp"/>
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/txt_time_preview"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Valgt: -"
|
||||
android:gravity="center"
|
||||
android:textStyle="bold"
|
||||
android:layout_marginBottom="24dp"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Velg Kalender:"
|
||||
android:textSize="14sp"
|
||||
android:textColor="#666"/>
|
||||
|
||||
<Spinner
|
||||
android:id="@+id/spinner_calendar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:padding="12dp"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Gjentakelse:"
|
||||
android:textSize="14sp"
|
||||
android:textColor="#666"/>
|
||||
|
||||
<Spinner
|
||||
android:id="@+id/spinner_recurrence"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:padding="12dp"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Varsling:"
|
||||
android:textSize="14sp"
|
||||
android:textColor="#666"/>
|
||||
|
||||
<Spinner
|
||||
android:id="@+id/spinner_reminder"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="32dp"
|
||||
android:padding="12dp"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_save_event"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Lagre i Kalender"
|
||||
android:backgroundTint="@color/kbs_logo_blue"
|
||||
android:textColor="#FFFFFF"/>
|
||||
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
|
|
@ -7,6 +7,7 @@
|
|||
android:padding="8dp"
|
||||
android:background="@color/kbs_very_light_blue">
|
||||
|
||||
<!-- OVERSKRIFT OG PROFIL -->
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
|
@ -33,6 +34,21 @@
|
|||
app:tint="@color/kbs_logo_blue"/>
|
||||
</RelativeLayout>
|
||||
|
||||
<!-- NYTT: KNAPP FOR Å OPPRETTE HENDELSE -->
|
||||
<!-- Denne var borte i din fil. Den settes til visibility="gone" som standard,
|
||||
og skrus på av Java-koden hvis brukeren er admin. -->
|
||||
<Button
|
||||
android:id="@+id/btn_create_event"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="+ Ny Kalenderhendelse"
|
||||
android:backgroundTint="@color/kbs_logo_blue"
|
||||
android:textColor="#FFFFFF"
|
||||
android:layout_marginHorizontal="8dp"
|
||||
android:layout_marginBottom="12dp"
|
||||
android:visibility="gone"/>
|
||||
|
||||
<!-- KALENDER-SEKSJON -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
|
@ -70,6 +86,7 @@
|
|||
android:scrollbars="vertical"
|
||||
android:layout_marginBottom="16dp"/>
|
||||
|
||||
<!-- NYHETER-SEKSJON -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
|
|
|||
|
|
@ -31,8 +31,19 @@
|
|||
<action
|
||||
android:id="@+id/action_home_to_newsDetail"
|
||||
app:destination="@id/navigation_news_detail" />
|
||||
<!-- HER ER DEN MANGLENDE LINKEN: -->
|
||||
<action
|
||||
android:id="@+id/action_home_to_create_event"
|
||||
app:destination="@id/navigation_create_event" />
|
||||
</fragment>
|
||||
|
||||
<!-- NYTT FRAGMENT: Opprett hendelse -->
|
||||
<fragment
|
||||
android:id="@+id/navigation_create_event"
|
||||
android:name="com.kbs.kbsintranett.CreateEventFragment"
|
||||
android:label="Ny Hendelse"
|
||||
tools:layout="@layout/fragment_create_event" />
|
||||
|
||||
<fragment
|
||||
android:id="@+id/navigation_calendar_full"
|
||||
android:name="com.kbs.kbsintranett.CalendarFullFragment"
|
||||
|
|
|
|||
|
|
@ -1,3 +1,10 @@
|
|||
<resources>
|
||||
<string name="app_name">KBS Intranett</string>
|
||||
<!-- NYTT: Array for gjentakelse-spinneren -->
|
||||
<string-array name="recurrence_freq_array">
|
||||
<item>dag</item>
|
||||
<item>uke</item>
|
||||
<item>måned</item>
|
||||
<item>år</item>
|
||||
</string-array>
|
||||
</resources>
|
||||
|
|
@ -7,4 +7,17 @@
|
|||
</style>
|
||||
|
||||
<style name="Theme.KBSIntranett" parent="Base.Theme.KBSIntranett" />
|
||||
|
||||
<!-- NYTT: Stil for runde ukedag-knapper (M T O T F L S) -->
|
||||
<style name="DayToggle">
|
||||
<item name="android:layout_width">0dp</item>
|
||||
<item name="android:layout_height">40dp</item>
|
||||
<item name="android:layout_weight">1</item>
|
||||
<item name="android:background">@drawable/selector_day_toggle</item>
|
||||
<item name="android:textColor">@color/selector_day_text</item>
|
||||
<item name="android:textOff">M</item>
|
||||
<item name="android:textOn">M</item>
|
||||
<item name="android:textSize">12sp</item>
|
||||
<item name="android:layout_margin">2dp</item>
|
||||
</style>
|
||||
</resources>
|
||||
Loading…
Reference in a new issue