Før Optimalisering Steg 2
This commit is contained in:
parent
ca1b8a647e
commit
710a192951
7 changed files with 426 additions and 314 deletions
189
app/src/main/java/com/kbs/kbsintranett/HomeAdapter.java
Normal file
189
app/src/main/java/com/kbs/kbsintranett/HomeAdapter.java
Normal file
|
|
@ -0,0 +1,189 @@
|
||||||
|
package com.kbs.kbsintranett;
|
||||||
|
|
||||||
|
import android.content.res.ColorStateList;
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.Button;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
import android.widget.LinearLayout;
|
||||||
|
import android.widget.TextView;
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.core.content.ContextCompat;
|
||||||
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
import com.bumptech.glide.Glide;
|
||||||
|
import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class HomeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
|
||||||
|
|
||||||
|
public static final int TYPE_HEADER = 0;
|
||||||
|
public static final int TYPE_CREATE_BUTTON = 1;
|
||||||
|
public static final int TYPE_SECTION_TITLE = 2;
|
||||||
|
public static final int TYPE_CALENDAR_ITEM = 3;
|
||||||
|
public static final int TYPE_NEWS_ITEM = 4;
|
||||||
|
|
||||||
|
private final List<Object> items;
|
||||||
|
private final OnHomeClickListener listener;
|
||||||
|
|
||||||
|
public interface OnHomeClickListener {
|
||||||
|
void onProfileClick();
|
||||||
|
void onCreateEventClick();
|
||||||
|
void onViewAllCalendarClick();
|
||||||
|
void onViewAllNewsClick();
|
||||||
|
void onCalendarItemClick(CalendarEvent event);
|
||||||
|
void onNewsItemClick(WpPost post);
|
||||||
|
}
|
||||||
|
|
||||||
|
public HomeAdapter(List<Object> items, OnHomeClickListener listener) {
|
||||||
|
this.items = items;
|
||||||
|
this.listener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getItemViewType(int position) {
|
||||||
|
Object item = items.get(position);
|
||||||
|
if (item instanceof HeaderItem) return TYPE_HEADER;
|
||||||
|
if (item instanceof CreateButtonItem) return TYPE_CREATE_BUTTON;
|
||||||
|
if (item instanceof SectionTitleItem) return TYPE_SECTION_TITLE;
|
||||||
|
if (item instanceof CalendarEvent) return TYPE_CALENDAR_ITEM;
|
||||||
|
if (item instanceof WpPost) return TYPE_NEWS_ITEM;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||||
|
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
|
||||||
|
switch (viewType) {
|
||||||
|
case TYPE_HEADER:
|
||||||
|
return new HeaderViewHolder(inflater.inflate(R.layout.item_home_header, parent, false));
|
||||||
|
case TYPE_CREATE_BUTTON:
|
||||||
|
return new CreateButtonViewHolder(inflater.inflate(R.layout.item_home_create_btn, parent, false));
|
||||||
|
case TYPE_SECTION_TITLE:
|
||||||
|
return new SectionTitleViewHolder(inflater.inflate(R.layout.item_home_section_title, parent, false));
|
||||||
|
case TYPE_CALENDAR_ITEM:
|
||||||
|
return new CalendarViewHolder(inflater.inflate(R.layout.item_calendar, parent, false));
|
||||||
|
case TYPE_NEWS_ITEM:
|
||||||
|
return new NewsViewHolder(inflater.inflate(R.layout.item_news, parent, false));
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("Ugyldig viewType");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
|
||||||
|
Object item = items.get(position);
|
||||||
|
|
||||||
|
if (holder instanceof HeaderViewHolder) {
|
||||||
|
((HeaderViewHolder) holder).btnProfile.setOnClickListener(v -> listener.onProfileClick());
|
||||||
|
}
|
||||||
|
else if (holder instanceof CreateButtonViewHolder) {
|
||||||
|
((CreateButtonViewHolder) holder).btnCreate.setOnClickListener(v -> listener.onCreateEventClick());
|
||||||
|
}
|
||||||
|
else if (holder instanceof SectionTitleViewHolder) {
|
||||||
|
SectionTitleItem section = (SectionTitleItem) item;
|
||||||
|
SectionTitleViewHolder vh = (SectionTitleViewHolder) holder;
|
||||||
|
vh.title.setText(section.title);
|
||||||
|
vh.btnViewAll.setOnClickListener(v -> {
|
||||||
|
if (section.isCalendar) listener.onViewAllCalendarClick();
|
||||||
|
else listener.onViewAllNewsClick();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else if (holder instanceof CalendarViewHolder) {
|
||||||
|
CalendarEvent event = (CalendarEvent) item;
|
||||||
|
CalendarViewHolder vh = (CalendarViewHolder) holder;
|
||||||
|
vh.day.setText(event.getDay());
|
||||||
|
vh.month.setText(event.getMonth());
|
||||||
|
vh.time.setText(event.getTime());
|
||||||
|
vh.title.setText(event.getTitle());
|
||||||
|
|
||||||
|
boolean isPrivate = event.getDescription() != null && event.getDescription().contains("#deltakere:");
|
||||||
|
int color;
|
||||||
|
try {
|
||||||
|
color = Color.parseColor(isPrivate ? "#673AB7" : event.getCalendarColor());
|
||||||
|
} catch (Exception e) {
|
||||||
|
color = Color.parseColor("#0069B3");
|
||||||
|
}
|
||||||
|
vh.dateBox.setBackgroundTintList(ColorStateList.valueOf(color));
|
||||||
|
vh.itemView.setOnClickListener(v -> listener.onCalendarItemClick(event));
|
||||||
|
}
|
||||||
|
else if (holder instanceof NewsViewHolder) {
|
||||||
|
WpPost post = (WpPost) item;
|
||||||
|
NewsViewHolder vh = (NewsViewHolder) holder;
|
||||||
|
vh.title.setText(post.getTitleStr());
|
||||||
|
vh.excerpt.setText(post.getExcerptStr());
|
||||||
|
vh.date.setText(post.date);
|
||||||
|
|
||||||
|
String cat = post.getCategoryName();
|
||||||
|
vh.category.setText(cat);
|
||||||
|
vh.category.setVisibility(cat.isEmpty() ? View.GONE : View.VISIBLE);
|
||||||
|
|
||||||
|
String imgUrl = post.getFeaturedImageUrl();
|
||||||
|
if (imgUrl != null) {
|
||||||
|
vh.image.setVisibility(View.VISIBLE);
|
||||||
|
Glide.with(vh.image.getContext()).load(imgUrl).transition(DrawableTransitionOptions.withCrossFade()).centerCrop().into(vh.image);
|
||||||
|
} else {
|
||||||
|
vh.image.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
vh.itemView.setOnClickListener(v -> listener.onNewsItemClick(post));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getItemCount() {
|
||||||
|
return items.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- VIEW HOLDERS ---
|
||||||
|
|
||||||
|
static class HeaderViewHolder extends RecyclerView.ViewHolder {
|
||||||
|
ImageView btnProfile;
|
||||||
|
HeaderViewHolder(View v) { super(v); btnProfile = v.findViewById(R.id.btn_profile); }
|
||||||
|
}
|
||||||
|
|
||||||
|
static class CreateButtonViewHolder extends RecyclerView.ViewHolder {
|
||||||
|
Button btnCreate;
|
||||||
|
CreateButtonViewHolder(View v) { super(v); btnCreate = v.findViewById(R.id.btn_create_event); }
|
||||||
|
}
|
||||||
|
|
||||||
|
static class SectionTitleViewHolder extends RecyclerView.ViewHolder {
|
||||||
|
TextView title, btnViewAll;
|
||||||
|
SectionTitleViewHolder(View v) { super(v); title = v.findViewById(R.id.txt_section_title); btnViewAll = v.findViewById(R.id.btn_view_all); }
|
||||||
|
}
|
||||||
|
|
||||||
|
static class CalendarViewHolder extends RecyclerView.ViewHolder {
|
||||||
|
TextView day, month, title, time;
|
||||||
|
LinearLayout dateBox;
|
||||||
|
CalendarViewHolder(View v) {
|
||||||
|
super(v);
|
||||||
|
day = v.findViewById(R.id.cal_day);
|
||||||
|
month = v.findViewById(R.id.cal_month);
|
||||||
|
title = v.findViewById(R.id.cal_title);
|
||||||
|
time = v.findViewById(R.id.cal_time);
|
||||||
|
dateBox = v.findViewById(R.id.date_box_background);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class NewsViewHolder extends RecyclerView.ViewHolder {
|
||||||
|
TextView title, excerpt, date, category;
|
||||||
|
ImageView image;
|
||||||
|
NewsViewHolder(View v) {
|
||||||
|
super(v);
|
||||||
|
title = v.findViewById(R.id.news_title);
|
||||||
|
excerpt = v.findViewById(R.id.news_excerpt);
|
||||||
|
date = v.findViewById(R.id.news_date);
|
||||||
|
category = v.findViewById(R.id.news_category);
|
||||||
|
image = v.findViewById(R.id.news_image);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- WRAPPER KLASSER FOR FLATE LISTER ---
|
||||||
|
public static class HeaderItem {}
|
||||||
|
public static class CreateButtonItem {}
|
||||||
|
public static class SectionTitleItem {
|
||||||
|
String title; boolean isCalendar;
|
||||||
|
public SectionTitleItem(String t, boolean c) { this.title = t; this.isCalendar = c; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -8,9 +8,7 @@ import android.os.Looper;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.Button;
|
|
||||||
import android.widget.ProgressBar;
|
import android.widget.ProgressBar;
|
||||||
import android.widget.TextView;
|
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
import androidx.activity.result.ActivityResultLauncher;
|
import androidx.activity.result.ActivityResultLauncher;
|
||||||
import androidx.activity.result.contract.ActivityResultContracts;
|
import androidx.activity.result.contract.ActivityResultContracts;
|
||||||
|
|
@ -32,27 +30,26 @@ import retrofit2.Call;
|
||||||
import retrofit2.Callback;
|
import retrofit2.Callback;
|
||||||
import retrofit2.Response;
|
import retrofit2.Response;
|
||||||
|
|
||||||
public class HomeFragment extends Fragment {
|
public class HomeFragment extends Fragment implements HomeAdapter.OnHomeClickListener {
|
||||||
private ActivityResultLauncher<String> requestPermissionLauncher;
|
|
||||||
private RecyclerView calendarRecycler;
|
private RecyclerView recyclerView;
|
||||||
private RecyclerView newsRecycler;
|
private HomeAdapter adapter;
|
||||||
private ProgressBar mainProgressBar;
|
private ProgressBar mainProgressBar;
|
||||||
private SwipeRefreshLayout swipeRefreshLayout;
|
private SwipeRefreshLayout swipeRefreshLayout;
|
||||||
|
|
||||||
|
private List<CalendarEvent> currentEvents = new ArrayList<>();
|
||||||
|
private List<WpPost> currentNews = new ArrayList<>();
|
||||||
private int activeNetworkCalls = 0;
|
private int activeNetworkCalls = 0;
|
||||||
|
|
||||||
|
private ActivityResultLauncher<String> requestPermissionLauncher;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
requestPermissionLauncher = registerForActivityResult(
|
requestPermissionLauncher = registerForActivityResult(
|
||||||
new ActivityResultContracts.RequestPermission(),
|
new ActivityResultContracts.RequestPermission(),
|
||||||
isGranted -> {
|
isGranted -> refreshData()
|
||||||
if (calendarRecycler != null) {
|
|
||||||
refreshData();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
// GAMMEL METODE FJERNET HERFRA (startNotificationWorker)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
|
|
@ -66,76 +63,101 @@ public class HomeFragment extends Fragment {
|
||||||
super.onViewCreated(view, savedInstanceState);
|
super.onViewCreated(view, savedInstanceState);
|
||||||
|
|
||||||
mainProgressBar = view.findViewById(R.id.main_loading_spinner);
|
mainProgressBar = view.findViewById(R.id.main_loading_spinner);
|
||||||
if (mainProgressBar != null) mainProgressBar.setVisibility(View.VISIBLE);
|
|
||||||
|
|
||||||
swipeRefreshLayout = view.findViewById(R.id.swipe_refresh_home);
|
swipeRefreshLayout = view.findViewById(R.id.swipe_refresh_home);
|
||||||
|
recyclerView = view.findViewById(R.id.main_recycler_view);
|
||||||
|
|
||||||
|
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
|
||||||
swipeRefreshLayout.setOnRefreshListener(this::refreshData);
|
swipeRefreshLayout.setOnRefreshListener(this::refreshData);
|
||||||
|
|
||||||
View profileBtn = view.findViewById(R.id.btn_profile);
|
|
||||||
if (profileBtn != null) {
|
|
||||||
profileBtn.setOnClickListener(v -> Navigation.findNavController(view).navigate(R.id.navigation_profile));
|
|
||||||
}
|
|
||||||
|
|
||||||
Button btnCreateEvent = view.findViewById(R.id.btn_create_event);
|
|
||||||
List<String> writeable = UserManager.getInstance().getWriteableCalendars();
|
|
||||||
if (writeable != null && !writeable.isEmpty()) {
|
|
||||||
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 -> {}));
|
|
||||||
|
|
||||||
TextView viewAllCalendar = view.findViewById(R.id.btn_view_all_calendar);
|
|
||||||
if (viewAllCalendar != null) {
|
|
||||||
viewAllCalendar.setOnClickListener(v -> Navigation.findNavController(view).navigate(R.id.action_home_to_calendarFull));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (android.os.Build.VERSION.SDK_INT >= 33) {
|
if (android.os.Build.VERSION.SDK_INT >= 33) {
|
||||||
if (ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) {
|
if (ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) {
|
||||||
registerForActivityResult(new ActivityResultContracts.RequestPermission(), isGranted -> {}).launch(Manifest.permission.POST_NOTIFICATIONS);
|
requestPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
newsRecycler = view.findViewById(R.id.recycler_news);
|
|
||||||
newsRecycler.setLayoutManager(new LinearLayoutManager(getContext()));
|
|
||||||
newsRecycler.setNestedScrollingEnabled(false);
|
|
||||||
newsRecycler.setAdapter(new NewsAdapter(new ArrayList<>(), item -> {}));
|
|
||||||
|
|
||||||
TextView viewAllNews = view.findViewById(R.id.btn_view_all_news);
|
|
||||||
if (viewAllNews != null) {
|
|
||||||
viewAllNews.setOnClickListener(v -> {
|
|
||||||
Navigation.findNavController(view).navigate(R.id.action_home_to_newsFull);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
refreshData();
|
refreshData();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onResume() {
|
|
||||||
super.onResume();
|
|
||||||
if (activeNetworkCalls == 0) {
|
|
||||||
refreshData();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void refreshData() {
|
private void refreshData() {
|
||||||
|
if (activeNetworkCalls > 0) return;
|
||||||
activeNetworkCalls = 2;
|
activeNetworkCalls = 2;
|
||||||
|
if (mainProgressBar != null) mainProgressBar.setVisibility(View.VISIBLE);
|
||||||
|
|
||||||
if (ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.READ_CALENDAR) == PackageManager.PERMISSION_GRANTED) {
|
fetchCalendarData();
|
||||||
fetchCalendarEvents(calendarRecycler);
|
fetchNewsData();
|
||||||
} else {
|
|
||||||
checkLoadingComplete();
|
|
||||||
requestPermissionLauncher.launch(Manifest.permission.READ_CALENDAR);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fetchNewsFromWordpress(newsRecycler);
|
private void fetchCalendarData() {
|
||||||
|
if (ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.READ_CALENDAR) != PackageManager.PERMISSION_GRANTED) {
|
||||||
|
requestPermissionLauncher.launch(Manifest.permission.READ_CALENDAR);
|
||||||
|
currentEvents.clear();
|
||||||
|
checkLoadingComplete();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
new Thread(() -> {
|
||||||
|
List<CalendarEvent> deviceEvents = CalendarManager.getDeviceEvents(getContext(), true);
|
||||||
|
new Handler(Looper.getMainLooper()).post(() -> {
|
||||||
|
RetrofitClient.getApiService().getCalendarEvents().enqueue(new Callback<List<CalendarEvent>>() {
|
||||||
|
@Override
|
||||||
|
public void onResponse(Call<List<CalendarEvent>> call, Response<List<CalendarEvent>> response) {
|
||||||
|
List<CalendarEvent> apiEvents = new ArrayList<>();
|
||||||
|
if (response.isSuccessful() && response.body() != null) {
|
||||||
|
apiEvents = response.body();
|
||||||
|
CacheManager.saveCalendarEvents(getContext(), apiEvents);
|
||||||
|
} else {
|
||||||
|
apiEvents = CacheManager.getCachedCalendarEvents(getContext());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (CalendarEvent e : apiEvents) CalendarManager.formatEventForUI(e);
|
||||||
|
currentEvents = CalendarManager.mergeAndSort(apiEvents, deviceEvents);
|
||||||
|
checkLoadingComplete();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Call<List<CalendarEvent>> call, Throwable t) {
|
||||||
|
List<CalendarEvent> cached = CacheManager.getCachedCalendarEvents(getContext());
|
||||||
|
for (CalendarEvent e : cached) CalendarManager.formatEventForUI(e);
|
||||||
|
currentEvents = CalendarManager.mergeAndSort(cached, deviceEvents);
|
||||||
|
checkLoadingComplete();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}).start();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void fetchNewsData() {
|
||||||
|
RetrofitClient.getApiService().getPosts().enqueue(new Callback<List<WpPost>>() {
|
||||||
|
@Override
|
||||||
|
public void onResponse(Call<List<WpPost>> call, Response<List<WpPost>> response) {
|
||||||
|
if (response.isSuccessful() && response.body() != null) {
|
||||||
|
currentNews = response.body();
|
||||||
|
CacheManager.saveNewsPosts(getContext(), currentNews);
|
||||||
|
} else {
|
||||||
|
currentNews = CacheManager.getCachedNewsPosts(getContext());
|
||||||
|
}
|
||||||
|
formatNewsDates(currentNews);
|
||||||
|
checkLoadingComplete();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Call<List<WpPost>> call, Throwable t) {
|
||||||
|
currentNews = CacheManager.getCachedNewsPosts(getContext());
|
||||||
|
formatNewsDates(currentNews);
|
||||||
|
checkLoadingComplete();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void formatNewsDates(List<WpPost> posts) {
|
||||||
|
SimpleDateFormat rawFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.getDefault());
|
||||||
|
SimpleDateFormat targetFormat = new SimpleDateFormat("dd. MMM yyyy", Locale.getDefault());
|
||||||
|
for (WpPost post : posts) {
|
||||||
|
try {
|
||||||
|
Date date = rawFormat.parse(post.date);
|
||||||
|
post.date = targetFormat.format(date);
|
||||||
|
} catch (Exception ignored) {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkLoadingComplete() {
|
private void checkLoadingComplete() {
|
||||||
|
|
@ -143,140 +165,58 @@ public class HomeFragment extends Fragment {
|
||||||
if (activeNetworkCalls <= 0) {
|
if (activeNetworkCalls <= 0) {
|
||||||
activeNetworkCalls = 0;
|
activeNetworkCalls = 0;
|
||||||
if (mainProgressBar != null) mainProgressBar.setVisibility(View.GONE);
|
if (mainProgressBar != null) mainProgressBar.setVisibility(View.GONE);
|
||||||
if (swipeRefreshLayout != null) swipeRefreshLayout.setRefreshing(false);
|
swipeRefreshLayout.setRefreshing(false);
|
||||||
|
buildAndDisplayList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void fetchCalendarEvents(RecyclerView recyclerView) {
|
private void buildAndDisplayList() {
|
||||||
new Thread(() -> {
|
List<Object> items = new ArrayList<>();
|
||||||
List<CalendarEvent> deviceEvents = CalendarManager.getDeviceEvents(getContext(), true);
|
|
||||||
new Handler(Looper.getMainLooper()).post(() -> fetchApiEvents(recyclerView, deviceEvents));
|
// 1. Header
|
||||||
}).start();
|
items.add(new HomeAdapter.HeaderItem());
|
||||||
|
|
||||||
|
// 2. Create Event Knapp (hvis tilgang)
|
||||||
|
if (!UserManager.getInstance().getWriteableCalendars().isEmpty()) {
|
||||||
|
items.add(new HomeAdapter.CreateButtonItem());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void fetchApiEvents(RecyclerView recyclerView, List<CalendarEvent> deviceEvents) {
|
// 3. Kalender Seksjon
|
||||||
RetrofitClient.getApiService().getCalendarEvents().enqueue(new Callback<List<CalendarEvent>>() {
|
items.add(new HomeAdapter.SectionTitleItem("Kommende hendelser", true));
|
||||||
@Override
|
|
||||||
public void onResponse(Call<List<CalendarEvent>> call, Response<List<CalendarEvent>> response) {
|
|
||||||
if (!isAdded()) return;
|
|
||||||
|
|
||||||
List<CalendarEvent> apiEvents = new ArrayList<>();
|
|
||||||
if (response.isSuccessful() && response.body() != null) {
|
|
||||||
apiEvents = response.body();
|
|
||||||
|
|
||||||
CacheManager.saveCalendarEvents(getContext(), apiEvents);
|
|
||||||
|
|
||||||
for (CalendarEvent e : apiEvents) {
|
|
||||||
CalendarManager.formatEventForUI(e);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
apiEvents = CacheManager.getCachedCalendarEvents(getContext());
|
|
||||||
for (CalendarEvent e : apiEvents) CalendarManager.formatEventForUI(e);
|
|
||||||
if (!apiEvents.isEmpty()) {
|
|
||||||
Toast.makeText(getContext(), "Server utilgjengelig. Viser lagret kalender.", Toast.LENGTH_SHORT).show();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
updateCalendarUI(recyclerView, apiEvents, deviceEvents);
|
|
||||||
checkLoadingComplete();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onFailure(Call<List<CalendarEvent>> call, Throwable t) {
|
|
||||||
if (!isAdded()) return;
|
|
||||||
|
|
||||||
List<CalendarEvent> cachedApiEvents = CacheManager.getCachedCalendarEvents(getContext());
|
|
||||||
for (CalendarEvent e : cachedApiEvents) CalendarManager.formatEventForUI(e);
|
|
||||||
|
|
||||||
if (!cachedApiEvents.isEmpty()) {
|
|
||||||
Toast.makeText(getContext(), "Ingen nettverk. Viser lagret kalender.", Toast.LENGTH_SHORT).show();
|
|
||||||
}
|
|
||||||
|
|
||||||
updateCalendarUI(recyclerView, cachedApiEvents, deviceEvents);
|
|
||||||
checkLoadingComplete();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateCalendarUI(RecyclerView recyclerView, List<CalendarEvent> apiEvents, List<CalendarEvent> deviceEvents) {
|
|
||||||
List<CalendarEvent> merged = CalendarManager.mergeAndSort(apiEvents, deviceEvents);
|
|
||||||
List<CalendarEvent> upcomingEvents = new ArrayList<>();
|
|
||||||
String today = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).format(new Date());
|
String today = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).format(new Date());
|
||||||
|
int count = 0;
|
||||||
for (CalendarEvent e : merged) {
|
for (CalendarEvent e : currentEvents) {
|
||||||
if (e.getRawDate() != null && e.getRawDate().compareTo(today) >= 0) {
|
if (e.getRawDate() != null && e.getRawDate().compareTo(today) >= 0) {
|
||||||
upcomingEvents.add(e);
|
items.add(e);
|
||||||
|
count++;
|
||||||
}
|
}
|
||||||
|
if (count >= 3) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<CalendarEvent> topEvents = new ArrayList<>();
|
// 4. Nyheter Seksjon
|
||||||
for(int i=0; i<Math.min(upcomingEvents.size(), 5); i++) {
|
items.add(new HomeAdapter.SectionTitleItem("Siste nytt", false));
|
||||||
topEvents.add(upcomingEvents.get(i));
|
items.addAll(currentNews);
|
||||||
|
|
||||||
|
adapter = new HomeAdapter(items, this);
|
||||||
|
recyclerView.setAdapter(adapter);
|
||||||
}
|
}
|
||||||
|
|
||||||
recyclerView.setAdapter(new CalendarAdapter(topEvents, event -> {
|
// --- KLIKKHÅNDTERING (Implementert fra HomeAdapter.OnHomeClickListener) ---
|
||||||
|
|
||||||
|
@Override public void onProfileClick() { Navigation.findNavController(getView()).navigate(R.id.navigation_profile); }
|
||||||
|
@Override public void onCreateEventClick() { Navigation.findNavController(getView()).navigate(R.id.action_home_to_create_event); }
|
||||||
|
@Override public void onViewAllCalendarClick() { Navigation.findNavController(getView()).navigate(R.id.action_home_to_calendarFull); }
|
||||||
|
@Override public void onViewAllNewsClick() { Navigation.findNavController(getView()).navigate(R.id.action_home_to_newsFull); }
|
||||||
|
|
||||||
|
@Override public void onCalendarItemClick(CalendarEvent event) {
|
||||||
CalendarDetailsBottomSheet sheet = new CalendarDetailsBottomSheet(event);
|
CalendarDetailsBottomSheet sheet = new CalendarDetailsBottomSheet(event);
|
||||||
sheet.setOnEventChangeListener(HomeFragment.this::refreshData);
|
sheet.setOnEventChangeListener(this::refreshData);
|
||||||
sheet.show(getParentFragmentManager(), "CalendarDetails");
|
sheet.show(getParentFragmentManager(), "CalendarDetails");
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void fetchNewsFromWordpress(RecyclerView recyclerView) {
|
@Override public void onNewsItemClick(WpPost post) {
|
||||||
WordPressApiService apiService = RetrofitClient.getApiService();
|
|
||||||
apiService.getPosts().enqueue(new Callback<List<WpPost>>() {
|
|
||||||
@Override
|
|
||||||
public void onResponse(Call<List<WpPost>> call, Response<List<WpPost>> response) {
|
|
||||||
if (getContext() == null) return;
|
|
||||||
|
|
||||||
List<WpPost> postsToShow = new ArrayList<>();
|
|
||||||
|
|
||||||
if (response.isSuccessful() && response.body() != null) {
|
|
||||||
postsToShow = response.body();
|
|
||||||
CacheManager.saveNewsPosts(getContext(), postsToShow);
|
|
||||||
} else {
|
|
||||||
postsToShow = CacheManager.getCachedNewsPosts(getContext());
|
|
||||||
if (!postsToShow.isEmpty()) {
|
|
||||||
Toast.makeText(getContext(), "Server utilgjengelig. Viser lagrede nyheter.", Toast.LENGTH_SHORT).show();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
updateNewsUI(recyclerView, postsToShow);
|
|
||||||
checkLoadingComplete();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onFailure(Call<List<WpPost>> call, Throwable t) {
|
|
||||||
if (getContext() == null) return;
|
|
||||||
|
|
||||||
List<WpPost> cachedPosts = CacheManager.getCachedNewsPosts(getContext());
|
|
||||||
if (!cachedPosts.isEmpty()) {
|
|
||||||
Toast.makeText(getContext(), "Ingen nettverk. Viser lagrede nyheter.", Toast.LENGTH_SHORT).show();
|
|
||||||
}
|
|
||||||
|
|
||||||
updateNewsUI(recyclerView, cachedPosts);
|
|
||||||
checkLoadingComplete();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateNewsUI(RecyclerView recyclerView, List<WpPost> posts) {
|
|
||||||
SimpleDateFormat rawFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.getDefault());
|
|
||||||
rawFormat.setTimeZone(TimeZone.getTimeZone("Europe/Oslo"));
|
|
||||||
SimpleDateFormat targetFormat = new SimpleDateFormat("dd. MMM yyyy", Locale.getDefault());
|
|
||||||
targetFormat.setTimeZone(TimeZone.getTimeZone("Europe/Oslo"));
|
|
||||||
|
|
||||||
for (WpPost post : posts) {
|
|
||||||
try {
|
|
||||||
Date date = rawFormat.parse(post.date);
|
|
||||||
post.date = targetFormat.format(date);
|
|
||||||
} catch (Exception e) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
NewsAdapter adapter = new NewsAdapter(posts, post -> {
|
|
||||||
Bundle bundle = new Bundle();
|
Bundle bundle = new Bundle();
|
||||||
bundle.putSerializable("post_data", post);
|
bundle.putSerializable("post_data", post);
|
||||||
Navigation.findNavController(getView()).navigate(R.id.action_home_to_newsDetail, bundle);
|
Navigation.findNavController(getView()).navigate(R.id.action_home_to_newsDetail, bundle);
|
||||||
});
|
|
||||||
recyclerView.setAdapter(adapter);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -5,140 +5,21 @@
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:background="@color/kbs_very_light_blue">
|
android:background="@color/kbs_very_light_blue">
|
||||||
|
|
||||||
<!-- SwipeRefreshLayout må pakke inn det skrollbare innholdet -->
|
|
||||||
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||||
android:id="@+id/swipe_refresh_home"
|
android:id="@+id/swipe_refresh_home"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
<androidx.core.widget.NestedScrollView
|
<!-- Én enkel RecyclerView som inneholder alt -->
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent">
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:padding="8dp">
|
|
||||||
|
|
||||||
<!-- OVERSKRIFT OG PROFIL -->
|
|
||||||
<RelativeLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginBottom="16dp"
|
|
||||||
android:paddingHorizontal="8dp">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="KBS Intranett"
|
|
||||||
android:textSize="24sp"
|
|
||||||
android:textStyle="bold"
|
|
||||||
android:textColor="@color/kbs_muted_blue_gray"
|
|
||||||
android:layout_centerVertical="true"/>
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/btn_profile"
|
|
||||||
android:layout_width="40dp"
|
|
||||||
android:layout_height="40dp"
|
|
||||||
android:src="@android:drawable/ic_menu_my_calendar"
|
|
||||||
android:background="?attr/selectableItemBackgroundBorderless"
|
|
||||||
android:layout_alignParentEnd="true"
|
|
||||||
android:layout_centerVertical="true"
|
|
||||||
app:tint="@color/kbs_logo_blue"/>
|
|
||||||
</RelativeLayout>
|
|
||||||
|
|
||||||
<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"
|
|
||||||
android:orientation="horizontal"
|
|
||||||
android:gravity="center_vertical"
|
|
||||||
android:layout_marginBottom="8dp"
|
|
||||||
android:layout_marginStart="8dp"
|
|
||||||
android:layout_marginEnd="8dp">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="1"
|
|
||||||
android:text="Kommende hendelser"
|
|
||||||
android:textSize="18sp"
|
|
||||||
android:textStyle="bold"
|
|
||||||
android:textColor="@color/black"/>
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/btn_view_all_calendar"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="Se alle >"
|
|
||||||
android:textColor="@color/kbs_logo_blue"
|
|
||||||
android:textStyle="bold"
|
|
||||||
android:padding="8dp"
|
|
||||||
android:background="?attr/selectableItemBackground"/>
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<!-- ENDRET: Fast høyde for å skape "vindu" med scroll -->
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
android:id="@+id/recycler_calendar"
|
android:id="@+id/main_recycler_view"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="190dp"
|
android:layout_height="match_parent"
|
||||||
android:scrollbars="vertical"
|
android:clipToPadding="false"
|
||||||
android:layout_marginBottom="16dp"/>
|
android:paddingBottom="16dp" />
|
||||||
|
|
||||||
<!-- NYHETER-SEKSJON -->
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="horizontal"
|
|
||||||
android:gravity="center_vertical"
|
|
||||||
android:layout_marginBottom="8dp"
|
|
||||||
android:layout_marginStart="8dp"
|
|
||||||
android:layout_marginEnd="8dp">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="1"
|
|
||||||
android:text="Siste nytt"
|
|
||||||
android:textSize="18sp"
|
|
||||||
android:textStyle="bold"
|
|
||||||
android:textColor="@color/black"/>
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/btn_view_all_news"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="Se alle >"
|
|
||||||
android:textColor="@color/kbs_logo_blue"
|
|
||||||
android:textStyle="bold"
|
|
||||||
android:padding="8dp"
|
|
||||||
android:background="?attr/selectableItemBackground"/>
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
|
||||||
android:id="@+id/recycler_news"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:nestedScrollingEnabled="false"
|
|
||||||
android:scrollbars="vertical"/>
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
</androidx.core.widget.NestedScrollView>
|
|
||||||
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
||||||
|
|
||||||
<!-- Initial Loader -->
|
|
||||||
<ProgressBar
|
<ProgressBar
|
||||||
android:id="@+id/main_loading_spinner"
|
android:id="@+id/main_loading_spinner"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
|
|
|
||||||
10
app/src/main/res/layout/item_home_create_btn.xml
Normal file
10
app/src/main/res/layout/item_home_create_btn.xml
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Button xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
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="16dp"
|
||||||
|
android:layout_marginBottom="16dp"/>
|
||||||
25
app/src/main/res/layout/item_home_header.xml
Normal file
25
app/src/main/res/layout/item_home_header.xml
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="KBS Intranett"
|
||||||
|
android:textSize="24sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:textColor="@color/kbs_muted_blue_gray"
|
||||||
|
android:layout_centerVertical="true"/>
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/btn_profile"
|
||||||
|
android:layout_width="40dp"
|
||||||
|
android:layout_height="40dp"
|
||||||
|
android:src="@android:drawable/ic_menu_my_calendar"
|
||||||
|
android:background="?attr/selectableItemBackgroundBorderless"
|
||||||
|
android:layout_alignParentEnd="true"
|
||||||
|
app:tint="@color/kbs_logo_blue"/>
|
||||||
|
</RelativeLayout>
|
||||||
29
app/src/main/res/layout/item_home_section_title.xml
Normal file
29
app/src/main/res/layout/item_home_section_title.xml
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:paddingHorizontal="16dp"
|
||||||
|
android:paddingVertical="8dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/txt_section_title"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="Seksjon"
|
||||||
|
android:textSize="18sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:textColor="@color/black"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/btn_view_all"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Se alle >"
|
||||||
|
android:textColor="@color/kbs_logo_blue"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:padding="8dp"
|
||||||
|
android:background="?attr/selectableItemBackground"/>
|
||||||
|
</LinearLayout>
|
||||||
38
app/src/main/res/menu/drawer_menu.xml
Normal file
38
app/src/main/res/menu/drawer_menu.xml
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<group android:checkableBehavior="single">
|
||||||
|
<item
|
||||||
|
android:id="@+id/navigation_home"
|
||||||
|
android:icon="@android:drawable/ic_menu_today"
|
||||||
|
android:title="Hjem" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/navigation_calendar_full"
|
||||||
|
android:icon="@android:drawable/ic_menu_my_calendar"
|
||||||
|
android:title="Kalender" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/navigation_tasks"
|
||||||
|
android:icon="@android:drawable/ic_menu_agenda"
|
||||||
|
android:title="Oppgaver" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/navigation_forms"
|
||||||
|
android:icon="@android:drawable/ic_menu_edit"
|
||||||
|
android:title="Skjemaer" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/navigation_news_full"
|
||||||
|
android:icon="@android:drawable/ic_menu_gallery"
|
||||||
|
android:title="Nyheter" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/navigation_handbook"
|
||||||
|
android:icon="@android:drawable/ic_menu_info_details"
|
||||||
|
android:title="Håndbok" />
|
||||||
|
</group>
|
||||||
|
|
||||||
|
<item android:title="Bruker">
|
||||||
|
<menu>
|
||||||
|
<item
|
||||||
|
android:id="@+id/navigation_profile"
|
||||||
|
android:icon="@android:drawable/ic_menu_manage"
|
||||||
|
android:title="Min Profil" />
|
||||||
|
</menu>
|
||||||
|
</item>
|
||||||
|
</menu>
|
||||||
Loading…
Reference in a new issue