Migliorato adapter avantielenco ordini di uscita

This commit is contained in:
Giuseppe Scorrano 2025-02-24 18:35:17 +01:00
parent 6c59e22101
commit 706878b1e4
15 changed files with 932 additions and 257 deletions

View File

@ -62,6 +62,9 @@ android {
android.buildFeatures.dataBinding true
android.buildFeatures.buildConfig true
android.dataBinding.enabledForTests true
android.dataBinding.addKtx true
compileOptions {
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17

View File

@ -168,14 +168,14 @@ public class MainApplicationModule {
@Provides
@Singleton
CommessaRESTConsumer provideCommessaRESTConsumer(SystemRESTConsumer systemRESTConsumer) {
return new CommessaRESTConsumer(systemRESTConsumer);
CommessaRESTConsumer provideCommessaRESTConsumer(ExecutorService executorService, SystemRESTConsumer systemRESTConsumer) {
return new CommessaRESTConsumer(executorService, systemRESTConsumer);
}
@Provides
@Singleton
DepositoRESTConsumer provideDepositoRESTConsumer(EntityRESTConsumer entityRESTConsumer, SystemRESTConsumer systemRESTConsumer) {
return new DepositoRESTConsumer(entityRESTConsumer, systemRESTConsumer);
DepositoRESTConsumer provideDepositoRESTConsumer(ExecutorService executorService, SystemRESTConsumer systemRESTConsumer) {
return new DepositoRESTConsumer(executorService, systemRESTConsumer);
}
@Provides

View File

@ -6,19 +6,28 @@ import androidx.databinding.ObservableArrayList;
import androidx.databinding.ObservableList;
import androidx.recyclerview.widget.RecyclerView;
import com.zhukic.sectionedrecyclerview.SectionedRecyclerViewAdapter;
import java.util.ArrayList;
import it.integry.integrywmsnative.core.expansion.OnListGeneralChangedCallback;
public abstract class ExtendedSectionedRecyclerView<T, SH extends RecyclerView.ViewHolder, VH extends RecyclerView.ViewHolder>
extends SectionedRecyclerViewAdapter<SH, VH> {
protected ArrayList<T> mDataset = new ArrayList<>();
private View mEmptyView;
public ExtendedSectionedRecyclerView(ObservableArrayList<T> myDataset) {
super();
mDataset.addAll(myDataset);
myDataset.addOnListChangedCallback(new OnListGeneralChangedCallback<T>() {
@Override
public void onChanged(ObservableList<T> sender) {
mDataset.clear();
mDataset.addAll(sender);
notifyDataChanged();
notifyDataSetChanged();
checkIfEmpty();
}
});
@ -32,11 +41,14 @@ public abstract class ExtendedSectionedRecyclerView<T, SH extends RecyclerView.V
return this;
}
@Override
public int getItemSize() {
return this.mDataset.size();
}
private void checkIfEmpty() {
if (mEmptyView != null) {
final boolean emptyViewVisible = getItemCount() == 0;
final boolean emptyViewVisible = getItemSize() == 0;
mEmptyView.setVisibility(emptyViewVisible ? View.VISIBLE : View.GONE);
}
}

View File

@ -0,0 +1,44 @@
package it.integry.integrywmsnative.core.expansion.view;
import android.view.View;
import androidx.databinding.ObservableArrayList;
import androidx.databinding.ObservableList;
import androidx.recyclerview.widget.RecyclerView;
import it.integry.integrywmsnative.core.expansion.OnListGeneralChangedCallback;
public abstract class ExtendedSectionedRecyclerViewNew<T, SH extends RecyclerView.ViewHolder, VH extends RecyclerView.ViewHolder>
extends SectionedRecyclerViewAdapter<SH, VH> {
private View mEmptyView;
public ExtendedSectionedRecyclerViewNew(ObservableArrayList<T> myDataset) {
super();
myDataset.addOnListChangedCallback(new OnListGeneralChangedCallback<T>() {
@Override
public void onChanged(ObservableList<T> sender) {
checkIfEmpty();
}
});
checkIfEmpty();
}
public ExtendedSectionedRecyclerViewNew<T, SH, VH> setEmptyView(View emptyView) {
this.mEmptyView = emptyView;
this.checkIfEmpty();
return this;
}
private void checkIfEmpty() {
if (mEmptyView != null) {
final boolean emptyViewVisible = getItemCount() == 0;
mEmptyView.setVisibility(emptyViewVisible ? View.VISIBLE : View.GONE);
}
}
}

View File

@ -0,0 +1,218 @@
package it.integry.integrywmsnative.core.expansion.view;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.util.SparseArray;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import java.lang.ref.WeakReference;
import java.util.ArrayDeque;
import java.util.HashSet;
import java.util.Locale;
import java.util.Set;
import java.util.concurrent.TimeUnit;
public class RecyclerViewProfiler {
private static final String TAG = "RVProfiler";
private final SparseArray<Long> bindingTimes;
private final SparseArray<Long> creationTimes;
private final Handler mainHandler;
private WeakReference<RecyclerView> recyclerViewRef;
private boolean isProfilingEnabled = true;
// Metriche di performance
private long totalBindingTime = 0;
private long totalCreationTime = 0;
private int bindCount = 0;
private int createCount = 0;
private long firstBindTime = 0;
private final ArrayDeque<Long> recentBindTimes;
private static final int MAX_RECENT_TIMES = 50;
public RecyclerViewProfiler(RecyclerView recyclerView) {
this.recyclerViewRef = new WeakReference<>(recyclerView);
this.bindingTimes = new SparseArray<>();
this.creationTimes = new SparseArray<>();
this.mainHandler = new Handler(Looper.getMainLooper());
this.recentBindTimes = new ArrayDeque<>();
setupRecyclerViewCallbacks();
}
private void setupRecyclerViewCallbacks() {
RecyclerView recyclerView = recyclerViewRef.get();
if (recyclerView == null) return;
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
logPerformanceMetrics();
}
}
});
// Monitora il pre-layout
recyclerView.addOnLayoutChangeListener((v, left, top, right, bottom,
oldLeft, oldTop, oldRight, oldBottom) -> {
if (firstBindTime == 0) {
mainHandler.postDelayed(this::checkInitialPerformance, 500);
}
});
}
public void onPreBind(int position) {
if (!isProfilingEnabled) return;
bindingTimes.put(position, System.nanoTime());
}
public void onPostBind(int position) {
if (!isProfilingEnabled) return;
Long startTime = bindingTimes.get(position);
if (startTime != null) {
long bindTime = System.nanoTime() - startTime;
bindingTimes.remove(position);
if (firstBindTime == 0) {
firstBindTime = bindTime;
}
totalBindingTime += bindTime;
bindCount++;
recentBindTimes.addLast(bindTime);
if (recentBindTimes.size() > MAX_RECENT_TIMES) {
recentBindTimes.removeFirst();
}
// Segnala binding lenti
if (bindTime > TimeUnit.MILLISECONDS.toNanos(16)) { // 1 frame
Log.w(TAG, String.format("Slow binding at position %d: %.2fms",
position, bindTime / 1_000_000.0));
}
}
}
public void onPreCreate(int viewType) {
if (!isProfilingEnabled) return;
creationTimes.put(viewType, System.nanoTime());
}
public void onPostCreate(int viewType) {
if (!isProfilingEnabled) return;
Long startTime = creationTimes.get(viewType);
if (startTime != null) {
long createTime = System.nanoTime() - startTime;
creationTimes.remove(viewType);
totalCreationTime += createTime;
createCount++;
// Segnala creazioni lente
if (createTime > TimeUnit.MILLISECONDS.toNanos(8)) {
Log.w(TAG, String.format("Slow view creation for type %d: %.2fms",
viewType, createTime / 1_000_000.0));
}
}
}
private void checkInitialPerformance() {
RecyclerView recyclerView = recyclerViewRef.get();
if (recyclerView == null) return;
// Verifica inflazione layout
long avgBindTime = bindCount > 0 ? totalBindingTime / bindCount : 0;
if (avgBindTime > TimeUnit.MILLISECONDS.toNanos(8)) {
Log.w(TAG, String.format("High average binding time: %.2fms. " +
"Consider using AsyncLayoutInflater", avgBindTime / 1_000_000.0));
}
// Verifica dimensione view pool
RecyclerView.RecycledViewPool pool = recyclerView.getRecycledViewPool();
if (pool != null) {
int[] viewTypes = getViewTypes(recyclerView);
for (int type : viewTypes) {
if (pool.getRecycledViewCount(type) == 0) {
Log.w(TAG, "ViewPool empty for type " + type +
". Consider increasing pool size");
}
}
}
// Verifica prefetch
if (recyclerView.getLayoutManager() instanceof LinearLayoutManager) {
LinearLayoutManager lm = (LinearLayoutManager) recyclerView.getLayoutManager();
if (!lm.isItemPrefetchEnabled()) {
Log.w(TAG, "Item prefetch is disabled. Enable it for better performance");
}
}
}
private void logPerformanceMetrics() {
if (!isProfilingEnabled || recentBindTimes.isEmpty()) return;
// Calcola la varianza dei tempi di binding recenti
double mean = recentBindTimes.stream()
.mapToLong(Long::longValue)
.average()
.orElse(0.0);
double variance = recentBindTimes.stream()
.mapToDouble(time -> Math.pow(time - mean, 2))
.average()
.orElse(0.0);
Log.d(TAG, String.format("Performance metrics:\n" +
"Avg binding time: %.2fms\n" +
"Binding time variance: %.2f\n" +
"View creation rate: %.1f%%",
mean / 1_000_000.0,
variance / 1_000_000.0,
createCount * 100.0 / (bindCount + 1)));
}
private int[] getViewTypes(RecyclerView recyclerView) {
RecyclerView.Adapter<?> adapter = recyclerView.getAdapter();
if (adapter == null) return new int[0];
Set<Integer> types = new HashSet<>();
for (int i = 0; i < adapter.getItemCount(); i++) {
types.add(adapter.getItemViewType(i));
}
return types.stream().mapToInt(Integer::intValue).toArray();
}
public void enableProfiling(boolean enabled) {
isProfilingEnabled = enabled;
if (!enabled) {
bindingTimes.clear();
creationTimes.clear();
recentBindTimes.clear();
}
}
public String getProfilingStats() {
if (bindCount == 0) return "No data collected yet";
return String.format(Locale.US,
"Profiling Statistics:\n" +
"Total bindings: %d\n" +
"Average binding time: %.2fms\n" +
"Total view creations: %d\n" +
"Average creation time: %.2fms\n" +
"First binding time: %.2fms\n" +
"Creation/Binding ratio: %.1f%%",
bindCount,
(totalBindingTime / bindCount) / 1_000_000.0,
createCount,
(totalCreationTime / createCount) / 1_000_000.0,
firstBindTime / 1_000_000.0,
createCount * 100.0 / bindCount);
}
}

View File

@ -0,0 +1,350 @@
package it.integry.integrywmsnative.core.expansion.view;
import android.util.SparseArray;
import android.util.SparseIntArray;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public abstract class SectionedRecyclerViewAdapter<H extends RecyclerView.ViewHolder,
I extends RecyclerView.ViewHolder> extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private RecyclerViewProfiler profiler;
private static final int TYPE_HEADER = 0;
private static final int TYPE_ITEM = 1;
// Utilizziamo SparseArray invece di HashMap per migliori performance su Android
private final SparseArray<Section> sectionsByPosition;
private final ArrayList<Section> sections;
// Cache per le posizioni degli item per evitare ricalcoli frequenti
private final SparseIntArray positionCache;
private int lastCacheUpdateCount;
// Pool di View per riutilizzo
private final RecyclerView.RecycledViewPool sharedPool;
// Dimensione massima della cache delle posizioni
private static final int MAX_POSITION_CACHE_SIZE = 2000;
public SectionedRecyclerViewAdapter() {
this.sections = new ArrayList<>();
this.sectionsByPosition = new SparseArray<>();
this.positionCache = new SparseIntArray(MAX_POSITION_CACHE_SIZE);
this.sharedPool = new RecyclerView.RecycledViewPool();
// Aumentiamo il pool di ViewHolder per tipo
sharedPool.setMaxRecycledViews(TYPE_HEADER, 50);
sharedPool.setMaxRecycledViews(TYPE_ITEM, 200);
}
@Override
public void onAttachedToRecyclerView(@NonNull RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
profiler = new RecyclerViewProfiler(recyclerView);
profiler.enableProfiling(false);
recyclerView.setRecycledViewPool(sharedPool);
// Ottimizziamo il layout manager per le prestazioni
if (recyclerView.getLayoutManager() instanceof LinearLayoutManager) {
LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
layoutManager.setItemPrefetchEnabled(true);
layoutManager.setInitialPrefetchItemCount(50);
}
// recyclerView.post(() -> {
// Precarica alcuni ViewHolder
// for (int i = 0; i < 25; i++) {
// sharedPool.putRecycledView(
// createViewHolder(recyclerView, TYPE_HEADER));
// }
// for (int i = 0; i < 50; i++) {
// sharedPool.putRecycledView(
// createViewHolder(recyclerView, TYPE_ITEM));
// }
// });
}
protected static class Section {
private final Object headerData;
private final ArrayList<Object> itemsData;
private int globalStartPosition; // Posizione globale di inizio sezione
public Section(Object headerData, int initialCapacity) {
this.headerData = headerData;
this.itemsData = new ArrayList<>(initialCapacity);
this.globalStartPosition = 0;
}
public Object getHeaderData() {
return headerData;
}
public List<Object> getItemsData() {
return itemsData;
}
public void addItem(Object item) {
itemsData.add(item);
}
public int getItemCount() {
return itemsData.size();
}
public void setGlobalStartPosition(int position) {
this.globalStartPosition = position;
}
public int getGlobalStartPosition() {
return globalStartPosition;
}
}
// ViewHolder pooling e caching
@Override
public void onViewRecycled(@NonNull RecyclerView.ViewHolder holder) {
super.onViewRecycled(holder);
// Pulizia custom del ViewHolder se necessario
if (holder instanceof OnRecycleListener) {
((OnRecycleListener) holder).onRecycle();
}
}
// Interfaccia per gestire la pulizia custom dei ViewHolder
public interface OnRecycleListener {
void onRecycle();
}
@Override
@NonNull
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
profiler.onPreCreate(viewType);
RecyclerView.ViewHolder holder;
if (viewType == TYPE_HEADER) {
holder = onCreateHeaderViewHolder(parent);
} else {
holder = onCreateItemViewHolder(parent);
}
// Applichiamo ViewHolder pooling
if (holder.itemView.getLayoutParams() == null) {
holder.itemView.setLayoutParams(
new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT
)
);
}
profiler.onPostCreate(viewType);
return holder;
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
profiler.onPreBind(position);
PositionInfo posInfo = getItemPositionInfo(position);
if (getItemViewType(position) == TYPE_HEADER) {
onBindHeaderViewHolder((H) holder,
sections.get(posInfo.sectionPosition).getHeaderData(),
posInfo.sectionPosition);
} else {
Section section = sections.get(posInfo.sectionPosition);
onBindItemViewHolder((I) holder,
section.getItemsData().get(posInfo.itemPosition),
posInfo.sectionPosition,
posInfo.itemPosition);
}
profiler.onPostBind(position);
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position, @NonNull List<Object> payloads) {
if (payloads.isEmpty()) {
super.onBindViewHolder(holder, position, payloads);
return;
}
// Supporto per aggiornamenti parziali
if (getItemViewType(position) == TYPE_HEADER) {
onBindHeaderViewHolderPartial((H) holder, position, payloads);
} else {
onBindItemViewHolderPartial((I) holder, position, payloads);
}
}
// Metodi per gestire aggiornamenti parziali
protected void onBindHeaderViewHolderPartial(H holder, int position, List<Object> payloads) {
onBindViewHolder(holder, position);
}
protected void onBindItemViewHolderPartial(I holder, int position, List<Object> payloads) {
onBindViewHolder(holder, position);
}
@Override
public int getItemCount() {
int count = 0;
for (Section section : sections) {
count += section.getItemCount() + 1;
}
return count;
}
@Override
public int getItemViewType(int position) {
return isHeader(position) ? TYPE_HEADER : TYPE_ITEM;
}
// Metodi ottimizzati per la gestione delle sezioni
public <T> void addSection(T headerData, int expectedItems) {
sections.add(new Section(headerData, expectedItems));
updatePositionCache();
notifyDataSetChanged();
}
public void addItem(int sectionPosition, Object item) {
if (sectionPosition >= 0 && sectionPosition < sections.size()) {
sections.get(sectionPosition).addItem(item);
updatePositionCache();
// Notifichiamo solo l'inserimento invece di un refresh completo
notifyItemInserted(getGlobalPositionForItem(sectionPosition,
sections.get(sectionPosition).getItemCount() - 1));
}
}
public <T extends Object, S extends Object> void setSections(List<T> headers, Map<T, List<S>> items) {
sections.clear();
sectionsByPosition.clear();
int position = 0;
for (T header : headers) {
List<S> sectionItems = items.get(header);
Section section = new Section(header, sectionItems != null ? sectionItems.size() : 5);
if (sectionItems != null) {
section.getItemsData().addAll(sectionItems);
}
section.setGlobalStartPosition(position);
sections.add(section);
sectionsByPosition.put(position, section);
position += section.getItemCount() + 1;
}
updatePositionCache();
notifyDataSetChanged();
}
// Gestione efficiente della cache delle posizioni
private void updatePositionCache() {
if (sections.size() > MAX_POSITION_CACHE_SIZE) {
positionCache.clear();
return;
}
int currentPosition = 0;
for (int i = 0; i < sections.size(); i++) {
Section section = sections.get(i);
section.setGlobalStartPosition(currentPosition);
sectionsByPosition.put(currentPosition, section);
currentPosition += section.getItemCount() + 1;
}
lastCacheUpdateCount = getItemCount();
}
private boolean isHeader(int position) {
Section section = sectionsByPosition.get(position);
if (section != null) {
return true;
}
for (int i = 0; i < sections.size(); i++) {
section = sections.get(i);
if (position == section.getGlobalStartPosition()) {
return true;
}
if (position < section.getGlobalStartPosition() + section.getItemCount() + 1) {
return false;
}
}
return false;
}
private static class PositionInfo {
final int sectionPosition;
final int itemPosition;
PositionInfo(int sectionPosition, int itemPosition) {
this.sectionPosition = sectionPosition;
this.itemPosition = itemPosition;
}
}
private PositionInfo getItemPositionInfo(int position) {
// Controllo cache
int cachedSection = positionCache.get(position, -1);
if (cachedSection != -1 && lastCacheUpdateCount == getItemCount()) {
Section section = sections.get(cachedSection);
int relativePos = position - section.getGlobalStartPosition();
if (relativePos == 0) {
return new PositionInfo(cachedSection, -1);
}
return new PositionInfo(cachedSection, relativePos - 1);
}
// Ricerca ottimizzata
Section targetSection = sectionsByPosition.get(position);
if (targetSection != null) {
int sectionIndex = sections.indexOf(targetSection);
return new PositionInfo(sectionIndex, -1);
}
// Ricerca binaria nelle sezioni
int left = 0;
int right = sections.size() - 1;
while (left <= right) {
int mid = (left + right) >>> 1;
Section section = sections.get(mid);
int sectionStart = section.getGlobalStartPosition();
int sectionEnd = sectionStart + section.getItemCount() + 1;
if (position >= sectionStart && position < sectionEnd) {
int relativePos = position - sectionStart;
if (relativePos == 0) {
return new PositionInfo(mid, -1);
}
return new PositionInfo(mid, relativePos - 1);
}
if (position < sectionStart) {
right = mid - 1;
} else {
left = mid + 1;
}
}
throw new IndexOutOfBoundsException("Position " + position + " is out of bounds");
}
private int getGlobalPositionForItem(int sectionPosition, int itemPosition) {
return sections.get(sectionPosition).getGlobalStartPosition() + itemPosition + 1;
}
// Metodi astratti che devono essere implementati
protected abstract H onCreateHeaderViewHolder(ViewGroup parent);
protected abstract I onCreateItemViewHolder(ViewGroup parent);
protected abstract void onBindHeaderViewHolder(H holder, Object headerData, int sectionPosition);
protected abstract void onBindItemViewHolder(I holder, Object itemData, int sectionPosition, int itemPosition);
}

View File

@ -178,7 +178,7 @@ public class ArticoloRESTConsumer extends _BaseRESTConsumer {
}
public void getArtsGroups(List<String> groupsToFind, RunnableArgs<List<MtbGrup>> onComplete, RunnableArgs<Exception> onFailed) {
public List<MtbGrup> getArtsGroupsSynchronized(List<String> groupsToFind) throws Exception {
var whereCondMap = Stream.of(groupsToFind)
.map(x -> {
HashMap<String, Object> vars = new HashMap<>();
@ -192,7 +192,18 @@ public class ArticoloRESTConsumer extends _BaseRESTConsumer {
Type typeOfObjectsList = new TypeToken<ArrayList<MtbGrup>>() {
}.getType();
this.systemRESTConsumer.processSql("SELECT * FROM mtb_grup " + whereCond, typeOfObjectsList, onComplete, onFailed);
return this.systemRESTConsumer.processSqlSynchronized("SELECT * FROM mtb_grup " + whereCond, typeOfObjectsList);
}
public void getArtsGroups(List<String> groupsToFind, RunnableArgs<List<MtbGrup>> onComplete, RunnableArgs<Exception> onFailed) {
executorService.execute(() -> {
try {
var data = getArtsGroupsSynchronized(groupsToFind);
if (onComplete != null) onComplete.run(data);
} catch (Exception ex) {
if (onFailed != null) onFailed.run(ex);
}
});
}

View File

@ -6,6 +6,7 @@ import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.stream.Collectors;
import javax.inject.Singleton;
@ -18,34 +19,42 @@ import it.integry.integrywmsnative.core.utility.UtilityString;
@Singleton
public class CommessaRESTConsumer extends _BaseRESTConsumer {
private final ExecutorService executorService;
private final SystemRESTConsumer systemRESTConsumer;
public CommessaRESTConsumer(SystemRESTConsumer systemRESTConsumer) {
public CommessaRESTConsumer(ExecutorService executorService, SystemRESTConsumer systemRESTConsumer) {
this.executorService = executorService;
this.systemRESTConsumer = systemRESTConsumer;
}
public void getJtbComts(List<String> itemsToFind, RunnableArgs<List<JtbComt>> onComplete, RunnableArgs<Exception> onFailed) {
var whereCondMap = itemsToFind.stream()
public List<JtbComt> getJtbComtsSynchronized(List<String> itemsToFind) throws Exception {
List<HashMap<String, Object>> whereCondMap = itemsToFind.stream()
.filter(x -> !UtilityString.isNullOrEmpty(x))
.map(x -> {
HashMap<String, Object> codJcom = new HashMap<>() {{
.map(x -> new HashMap<String, Object>() {{
put("cod_jcom", x);
}};
return codJcom;
})
}})
.collect(Collectors.toUnmodifiableList());
if(whereCondMap.isEmpty()) {
onComplete.run(new ArrayList<>());
return;
return new ArrayList<>();
}
var whereCond = " WHERE " + UtilityQuery.concatFieldListInWhereCond(whereCondMap);
Type typeOfObjectsList = new TypeToken<ArrayList<JtbComt>>() {}.getType();
this.systemRESTConsumer.processSql("SELECT * FROM jtb_comt " + whereCond, typeOfObjectsList, onComplete, onFailed);
return this.systemRESTConsumer.processSqlSynchronized("SELECT * FROM jtb_comt " + whereCond, typeOfObjectsList);
}
public void getJtbComts(List<String> itemsToFind, RunnableArgs<List<JtbComt>> onComplete, RunnableArgs<Exception> onFailed) {
executorService.execute(() -> {
try {
var data = getJtbComtsSynchronized(itemsToFind);
if (onComplete != null) onComplete.run(data);
} catch (Exception ex) {
if (onFailed != null) onFailed.run(ex);
}
});
}
}

View File

@ -5,26 +5,26 @@ import com.google.gson.reflect.TypeToken;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import javax.inject.Singleton;
import it.integry.integrywmsnative.core.expansion.RunnableArgs;
import it.integry.integrywmsnative.core.model.MtbDepo;
@Singleton
public class DepositoRESTConsumer extends _BaseRESTConsumer {
private final EntityRESTConsumer entityRESTConsumer;
private final ExecutorService executorService;
private final SystemRESTConsumer systemRESTConsumer;
public DepositoRESTConsumer(EntityRESTConsumer entityRESTConsumer, SystemRESTConsumer systemRESTConsumer) {
this.entityRESTConsumer = entityRESTConsumer;
public DepositoRESTConsumer(ExecutorService executorService, SystemRESTConsumer systemRESTConsumer) {
this.executorService = executorService;
this.systemRESTConsumer = systemRESTConsumer;
}
public void getAll(RunnableArgs<List<MtbDepo>> onComplete, RunnableArgs<Exception> onFailed) {
public List<MtbDepo> getAllSynchronized() throws Exception {
Type typeOfObjectsList = new TypeToken<ArrayList<MtbDepo>>() {
}.getType();
this.systemRESTConsumer.processSql("SELECT * FROM mtb_depo", typeOfObjectsList, onComplete, onFailed);
return this.systemRESTConsumer.processSqlSynchronized("SELECT * FROM mtb_depo", typeOfObjectsList);
}
}

View File

@ -2,6 +2,7 @@ package it.integry.integrywmsnative.gest.ordini_uscita_elenco;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.text.Html;
import android.view.LayoutInflater;
import android.view.View;
@ -93,6 +94,9 @@ public class OrdiniUscitaElencoFragment extends BaseFragment implements ITitledF
@Inject
OrdiniUscitaElencoViewModel mViewModel;
@Inject
Handler handler;
private final OrdiniUscitaElencoFiltroViewModel mAppliedFilterViewModel = new OrdiniUscitaElencoFiltroViewModel();
private FragmentMainOrdiniUscitaBinding mBindings = null;
@ -107,7 +111,7 @@ public class OrdiniUscitaElencoFragment extends BaseFragment implements ITitledF
private ElevatedToolbar mToolbar;
private final List<Runnable> mOnPreDestroyList = new ArrayList<>();
private int barcodeScannerIstanceID = -1;
private int mBarcodeScannerInstanceID = -1;
private List<MtbDepo> mtbDepoCache;
private List<MtbGrup> mtbGrupCache;
@ -175,18 +179,43 @@ public class OrdiniUscitaElencoFragment extends BaseFragment implements ITitledF
@Override
public void onStart() {
super.onStart();
this.onLoadingStarted();
this.initMtbDepoCache(() -> {
String codMdep = SettingsManager.i().getUserSession().getDepo().getCodMdep();
mViewModel.init(codMdep, mCurrentGestioneOrd, mCurrentGestioneCol, mCurrentSegnoCol);
this.mViewModel.getOrderList().observe(getViewLifecycleOwner(), data -> {
executorService.execute(() -> {
try {
this.onLoadingStarted();
this.initMtbGrupsCache();
this.initJtbComtCache();
mAppliedFilterViewModel.init(data);
this.refreshList(data, null);
this.onLoadingEnded();
} catch (Exception e) {
onError(e);
}
});
});
this.onLoadingStarted();
executorService.execute(() -> {
try {
this.initMtbDepoCache();
String codMdep = SettingsManager.i().getUserSession().getDepo().getCodMdep();
mViewModel.init(codMdep, mCurrentGestioneOrd, mCurrentGestioneCol, mCurrentSegnoCol);
this.onLoadingEnded();
} catch (Exception e) {
onError(e);
}
});
}
@Override
public void onDestroy() {
BarcodeManager.removeCallback(barcodeScannerIstanceID);
BarcodeManager.removeCallback(mBarcodeScannerInstanceID);
for (Runnable onPreDestroy : mOnPreDestroyList) {
onPreDestroy.run();
@ -198,19 +227,14 @@ public class OrdiniUscitaElencoFragment extends BaseFragment implements ITitledF
private void initRecyclerView() {
this.onLoadingStarted();
boolean canSelectMultipleOrdini = SettingsManager.iDB().isFlagSpedizioneCanSelectMultipleOrders();
boolean canSelectMultipleClienti = SettingsManager.iDB().isFlagMultiClienteOrdV();
this.mViewModel.getOrderList().observe(getViewLifecycleOwner(), v -> {
this.onLoadingStarted();
this.initMtbGrupsCache(() -> {
this.initJtbComtCache(this::onLoadingEnded);
});
executorService.execute(() -> {
mAppliedFilterViewModel.init(mViewModel.getOrderList().getValue());
this.refreshList(null);
});
OrdiniUscitaElencoAdapter ordiniUscitaElencoAdapter =
new OrdiniUscitaElencoAdapter(getActivity(), mOrdiniInevasiMutableData)
@ -243,26 +267,30 @@ public class OrdiniUscitaElencoFragment extends BaseFragment implements ITitledF
ordiniUscitaElencoAdapter
.setEmptyView(this.mBindings.ordiniVenditaEmptyView);
this.mBindings.venditaMainList.setAdapter(ordiniUscitaElencoAdapter);
this.mBindings.venditaMainList.setLayoutManager(new LinearLayoutManager(getActivity()));
this.mBindings.venditaMainList.setItemViewCacheSize(20);
this.mBindings.venditaMainList.setAdapter(ordiniUscitaElencoAdapter);
});
this.onLoadingEnded();
// if (mToolbar != null)
// mToolbar.setRecyclerView(this.mBindings.venditaMainList);
}
private void initBarcodeReader() {
barcodeScannerIstanceID = BarcodeManager.addCallback(new BarcodeCallbackDTO()
mBarcodeScannerInstanceID = BarcodeManager.addCallback(new BarcodeCallbackDTO()
.setOnScanSuccessful(onScanSuccessful)
.setOnScanFailed(ex -> UtilityExceptions.defaultException(getActivity(), ex, false)));
BarcodeManager.enable();
BarcodeManager.enable(mBarcodeScannerInstanceID);
}
private void initFilters() {
var onPredicateChanged = new OnGeneralChangedCallback() {
@Override
public void run() {
refreshList(null);
refreshList(mViewModel.getOrderList().getValue(), null);
}
};
@ -714,8 +742,7 @@ public class OrdiniUscitaElencoFragment extends BaseFragment implements ITitledF
this.mViewModel.processBarcodeDTO(data, this::onLoadingEnded);
};
private void refreshList(List<OrdiniUscitaElencoDTO> filteredList) {
requireActivity().runOnUiThread(() -> {
private void refreshList(List<OrdiniUscitaElencoDTO> originalData, List<OrdiniUscitaElencoDTO> filteredList) {
List<OrdiniUscitaElencoDTO> tmpList;
if (filteredList != null) {
@ -724,11 +751,12 @@ public class OrdiniUscitaElencoFragment extends BaseFragment implements ITitledF
mAppliedFilterViewModel.applyAllTests();
tmpList = mAppliedFilterViewModel.getMutableFilteredOrderList().getValue();
} else {
tmpList = mViewModel.getOrderList().getValue();
tmpList = originalData;
}
var list = convertDataModelToListModel(tmpList);
handler.post(() -> {
this.mOrdiniInevasiMutableData.clear();
this.mOrdiniInevasiMutableData.addAll(list);
@ -744,7 +772,7 @@ public class OrdiniUscitaElencoFragment extends BaseFragment implements ITitledF
.thenComparing(ComparatorCompat.comparing(x -> x.getDestinatario() != null ? x.getDestinatario() : "zzzzzzzzz"))
.thenComparing(ComparatorCompat.comparing(OrdiniUscitaElencoDTO::getNumOrd));
List<OrdiniUscitaElencoListModel> notHiddenElements = Stream.of(dataList)
List<OrdiniUscitaElencoListModel> notHiddenElements = dataList.parallelStream()
.filter(x -> !x.isHidden())
.sorted(comparator)
.map(x -> {
@ -774,7 +802,7 @@ public class OrdiniUscitaElencoFragment extends BaseFragment implements ITitledF
return listModel;
})
.toList();
.collect(Collectors.toList());
return notHiddenElements;
}
@ -814,7 +842,7 @@ public class OrdiniUscitaElencoFragment extends BaseFragment implements ITitledF
@Override
public void onOrderFiltered(List<OrdiniUscitaElencoDTO> filteredOrders) {
refreshList(filteredOrders);
refreshList(mViewModel.getOrderList().getValue(), filteredOrders);
}
@Override
@ -874,38 +902,34 @@ public class OrdiniUscitaElencoFragment extends BaseFragment implements ITitledF
}
private void initMtbDepoCache(Runnable onComplete) {
this.mDepositoRESTConsumer.getAll(mtbDepos -> {
private void initMtbDepoCache() throws Exception {
var mtbDepos = this.mDepositoRESTConsumer.getAllSynchronized();
this.mtbDepoCache = mtbDepos;
onComplete.run();
}, this::onError);
}
private void initMtbGrupsCache(Runnable onComplete) {
var codMgrpArts = Stream.of(Objects.requireNonNull(this.mViewModel.getOrderList().getValue()))
.flatMap(x -> Stream.of(x.getAvailableClassMerc() != null ? x.getAvailableClassMerc() : new ArrayList<>()))
private void initMtbGrupsCache() throws Exception {
var codMgrpArts = Objects.requireNonNull(this.mViewModel.getOrderList().getValue()).parallelStream()
.filter(x -> x.getAvailableClassMerc() != null && !x.getAvailableClassMerc().isEmpty())
.flatMap(x -> x.getAvailableClassMerc().stream())
.map(OrdineUscitaInevasoDTO.AvailableClassMerc::getCodMgrp)
.withoutNulls()
.filter(Objects::nonNull)
.distinct()
.toList();
.collect(Collectors.toList());
this.mArticoloRESTConsumer.getArtsGroups(codMgrpArts, mtbGrupCache -> {
var mtbGrupCache = this.mArticoloRESTConsumer.getArtsGroupsSynchronized(codMgrpArts);
this.mtbGrupCache = mtbGrupCache;
onComplete.run();
}, this::onError);
}
private void initJtbComtCache(Runnable onComplete) {
private void initJtbComtCache() throws Exception {
if (this.mViewModel.getOrderList().getValue() == null) {
this.jtbComtCache = new ArrayList<>();
onComplete.run();
return;
}
List<String> jtbComts = null;
if(this.mViewModel.getOrderList().getValue() != null) {
if (this.mViewModel.getOrderList().getValue() != null) {
jtbComts = this.mViewModel.getOrderList().getValue().stream()
.map(OrdineUscitaInevasoDTO::getCodJcom)
.distinct()
@ -915,13 +939,10 @@ public class OrdiniUscitaElencoFragment extends BaseFragment implements ITitledF
if (jtbComts == null || jtbComts.isEmpty()) {
this.jtbComtCache = new ArrayList<>();
onComplete.run();
return;
}
this.mCommessaRESTConsumer.getJtbComts(jtbComts, jtbComtCache -> {
var jtbComtCache = this.mCommessaRESTConsumer.getJtbComtsSynchronized(jtbComts);
this.jtbComtCache = jtbComtCache;
onComplete.run();
}, this::onError);
}
}

View File

@ -8,6 +8,8 @@ import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import javax.inject.Inject;
@ -57,19 +59,17 @@ public class OrdiniUscitaElencoViewModel {
}
public void init(String currentCodMdep, GestioneEnum gestioneOrd, GestioneEnum gestioneCol, int segnoCol) {
public void init(String currentCodMdep, GestioneEnum gestioneOrd, GestioneEnum gestioneCol, int segnoCol) throws Exception {
this.mCurrentCodMdep = currentCodMdep;
this.mCurrentGestioneOrd = gestioneOrd;
this.mCurrentGestioneCol = gestioneCol;
this.mCurrentSegnoCol = segnoCol;
this.sendOnLoadingStarted();
// Date loadingStartDate = new Date();
Date loadingStartDate = new Date();
var ordiniLavorazione = this.mOrdiniRESTConsumer.getOrdiniInevasiSynchronized(this.mCurrentCodMdep, mCurrentGestioneOrd);
this.mOrdiniRESTConsumer.getOrdiniInevasi(this.mCurrentCodMdep, mCurrentGestioneOrd,
ordiniLavorazione -> {
this.mOrderList.postValue(Stream.of(ordiniLavorazione)
var orderList = ordiniLavorazione.parallelStream()
.map(x -> {
try {
return OrdiniUscitaElencoDTO.fromParent(x);
@ -77,19 +77,19 @@ public class OrdiniUscitaElencoViewModel {
return null;
}
})
.toList());
.filter(Objects::nonNull)
.collect(Collectors.toList());
long forcedDelaySecs = (new Date().getTime() - loadingStartDate.getTime()) / 1000;
this.mOrderList.postValue(orderList);
if (2 - forcedDelaySecs > 0) {
try {
Thread.sleep((2 - forcedDelaySecs) * 1000);
} catch (Exception ignored) {
}
}
this.sendOnLoadingEnded();
}, this::sendError);
// long forcedDelaySecs = (new Date().getTime() - loadingStartDate.getTime()) / 1000;
//
// if (2 - forcedDelaySecs > 0) {
// try {
// Thread.sleep((2 - forcedDelaySecs) * 1000);
// } catch (Exception ignored) {
// }
// }
}

View File

@ -44,7 +44,7 @@ public class OrdiniUscitaElencoFiltroViewModel {
public void init(List<OrdiniUscitaElencoDTO> initialList) {
this.initialOrderList = initialList;
this.currentFilteredOrderList.setValue(this.initialOrderList);
this.currentFilteredOrderList.postValue(this.initialOrderList);
}
public MutableLiveData<List<OrdiniUscitaElencoDTO>> getMutableFilteredOrderList() {
@ -192,7 +192,7 @@ public class OrdiniUscitaElencoFiltroViewModel {
returnList = tmpStream.toList();
}
this.currentFilteredOrderList.setValue(returnList);
this.currentFilteredOrderList.postValue(returnList);
}
public ObservableField<Predicate<OrdiniUscitaElencoDTO>> getCurrentDepositoPredicate() {

View File

@ -8,24 +8,34 @@ import android.view.View;
import android.view.ViewGroup;
import androidx.core.content.res.ResourcesCompat;
import androidx.databinding.DataBindingUtil;
import androidx.databinding.ObservableArrayList;
import androidx.databinding.ObservableList;
import androidx.recyclerview.widget.RecyclerView;
import it.integry.integrywmsnative.R;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import it.integry.integrywmsnative.core.expansion.OnListGeneralChangedCallback;
import it.integry.integrywmsnative.core.expansion.OnSingleClickListener;
import it.integry.integrywmsnative.core.expansion.RunnableArgs;
import it.integry.integrywmsnative.core.expansion.view.ExtendedSectionedRecyclerView;
import it.integry.integrywmsnative.core.expansion.view.ExtendedSectionedRecyclerViewNew;
import it.integry.integrywmsnative.core.utility.UtilityString;
import it.integry.integrywmsnative.databinding.FragmentMainOrdiniUscitaListGroupModelBinding;
import it.integry.integrywmsnative.databinding.FragmentMainOrdiniUscitaListModelBinding;
public class OrdiniUscitaElencoAdapter extends ExtendedSectionedRecyclerView<OrdiniUscitaElencoListModel, OrdiniUscitaElencoAdapter.SubheaderHolder, OrdiniUscitaElencoAdapter.SingleItemViewHolder> {
public class OrdiniUscitaElencoAdapter extends ExtendedSectionedRecyclerViewNew<OrdiniUscitaElencoListModel, OrdiniUscitaElencoAdapter.SubheaderHolder, OrdiniUscitaElencoAdapter.SingleItemViewHolder> {
private final Context mContext;
// private final AsyncLayoutInflater asyncLayoutInflater;
private final LayoutInflater layoutInflater;
private RunnableArgs<String> mOnGroupItemClicked;
private RunnableArgs<OrdiniUscitaElencoListModel> mOnItemChecked;
static class SubheaderHolder extends RecyclerView.ViewHolder {
FragmentMainOrdiniUscitaListModelBinding mBinding;
@ -50,6 +60,22 @@ public class OrdiniUscitaElencoAdapter extends ExtendedSectionedRecyclerView<Ord
public OrdiniUscitaElencoAdapter(Context context, ObservableArrayList<OrdiniUscitaElencoListModel> mutableDataSet) {
super(mutableDataSet);
mContext = context;
layoutInflater = LayoutInflater.from(mContext);
// asyncLayoutInflater = new AsyncLayoutInflater(mContext);
mutableDataSet.addOnListChangedCallback(new OnListGeneralChangedCallback<OrdiniUscitaElencoListModel>() {
@Override
public void onChanged(ObservableList<OrdiniUscitaElencoListModel> sender) {
Map<String, List<OrdiniUscitaElencoListModel>> collect = sender.stream()
.collect(Collectors.groupingBy(OrdiniUscitaElencoListModel::getGroupTitle));
String[] keyArray = new String[collect.keySet().size()];
collect.keySet().toArray(keyArray);
setSections(Arrays.asList(keyArray), collect);
}
});
}
public OrdiniUscitaElencoAdapter setOnGroupItemClicked(RunnableArgs<String> onGroupItemClicked) {
@ -64,58 +90,60 @@ public class OrdiniUscitaElencoAdapter extends ExtendedSectionedRecyclerView<Ord
@Override
public OrdiniUscitaElencoAdapter.SubheaderHolder onCreateSubheaderViewHolder(ViewGroup parent, int viewType) {
FragmentMainOrdiniUscitaListModelBinding binding = DataBindingUtil.inflate(LayoutInflater.from(mContext), R.layout.fragment_main_ordini_uscita__list_model, parent, false);
public OrdiniUscitaElencoAdapter.SubheaderHolder onCreateHeaderViewHolder(ViewGroup parent) {
FragmentMainOrdiniUscitaListModelBinding binding = FragmentMainOrdiniUscitaListModelBinding.inflate(layoutInflater, parent, false);
return new OrdiniUscitaElencoAdapter.SubheaderHolder(binding);
}
@Override
public OrdiniUscitaElencoAdapter.SingleItemViewHolder onCreateItemViewHolder(ViewGroup parent, int viewType) {
FragmentMainOrdiniUscitaListGroupModelBinding binding = DataBindingUtil.inflate(LayoutInflater.from(mContext), R.layout.fragment_main_ordini_uscita__list_group_model, parent, false);
public OrdiniUscitaElencoAdapter.SingleItemViewHolder onCreateItemViewHolder(ViewGroup parent) {
FragmentMainOrdiniUscitaListGroupModelBinding binding = FragmentMainOrdiniUscitaListGroupModelBinding.inflate(layoutInflater, parent, false);
return new OrdiniUscitaElencoAdapter.SingleItemViewHolder(binding);
}
@Override
public void onBindSubheaderViewHolder(OrdiniUscitaElencoAdapter.SubheaderHolder subheaderHolder, int nextItemPosition) {
OrdiniUscitaElencoListModel pickingObjectDTO = this.mDataset.get(nextItemPosition);
public void onBindHeaderViewHolder(SubheaderHolder subheaderHolder, Object headerData, int nextItemPosition) {
String groupTitle = (String) headerData;
subheaderHolder.mBinding.groupTitle.setVisibility(UtilityString.isNullOrEmpty(pickingObjectDTO.getGroupTitle()) ? View.GONE : View.VISIBLE);
subheaderHolder.mBinding.groupTitle.setText(Html.fromHtml(pickingObjectDTO.getGroupTitle()));
subheaderHolder.mBinding.groupTitle.setVisibility(UtilityString.isNullOrEmpty(groupTitle) ? View.GONE : View.VISIBLE);
subheaderHolder.mBinding.groupTitle.setText(Html.fromHtml(groupTitle));
subheaderHolder.mBinding.getRoot().setOnClickListener(new OnSingleClickListener() {
@Override
public void onSingleClick(View v) {
if(mOnGroupItemClicked != null) mOnGroupItemClicked.run(pickingObjectDTO.getGroupTitle());
if (mOnGroupItemClicked != null)
mOnGroupItemClicked.run(groupTitle);
}
});
}
@Override
public void onBindItemViewHolder(final OrdiniUscitaElencoAdapter.SingleItemViewHolder holder, final int position) {
OrdiniUscitaElencoListModel listModel = this.mDataset.get(position);
public void onBindItemViewHolder(final SingleItemViewHolder holder, Object itemData, int sectionPosition, final int position) {
OrdiniUscitaElencoListModel listModel = (OrdiniUscitaElencoListModel) itemData;
listModel.getSelectedObservable().resetOnPropertyChangedCallback();
if(listModel.getEtichettaColor() != null)
if (listModel.getEtichettaColor() != null)
holder.mBinding.emptyView.setBackgroundColor(listModel.getEtichettaColor());
else holder.mBinding.emptyView.setBackgroundColor(ResourcesCompat.getColor(mContext.getResources(), android.R.color.transparent, null));
else
holder.mBinding.emptyView.setBackgroundColor(ResourcesCompat.getColor(mContext.getResources(), android.R.color.transparent, null));
if(!UtilityString.isNullOrEmpty(listModel.getDescription())) {
if (!UtilityString.isNullOrEmpty(listModel.getDescription())) {
holder.mBinding.descrizione.setText(Html.fromHtml(listModel.getDescription()));
holder.mBinding.descrizione.setVisibility(View.VISIBLE);
} else holder.mBinding.descrizione.setVisibility(View.GONE);
if(!UtilityString.isNullOrEmpty(listModel.getSubDescription())) {
if (!UtilityString.isNullOrEmpty(listModel.getSubDescription())) {
holder.mBinding.subDescrizione.setText(Html.fromHtml(listModel.getSubDescription()));
holder.mBinding.subDescrizione.setVisibility(View.VISIBLE);
} else holder.mBinding.subDescrizione.setVisibility(View.GONE);
if(!UtilityString.isNullOrEmpty(listModel.getRightDescription())) {
if (!UtilityString.isNullOrEmpty(listModel.getRightDescription())) {
holder.mBinding.rightDescrizione.setText(Html.fromHtml(listModel.getRightDescription()));
holder.mBinding.rightDescrizione.setVisibility(View.VISIBLE);
} else holder.mBinding.rightDescrizione.setVisibility(View.GONE);
if(!UtilityString.isNullOrEmpty(listModel.getRightSubDescription())) {
if (!UtilityString.isNullOrEmpty(listModel.getRightSubDescription())) {
holder.mBinding.rightSubDescrizione.setText(Html.fromHtml(listModel.getRightSubDescription()));
holder.mBinding.rightSubDescrizione.setVisibility(View.VISIBLE);
} else holder.mBinding.rightSubDescrizione.setVisibility(View.GONE);
@ -125,25 +153,11 @@ public class OrdiniUscitaElencoAdapter extends ExtendedSectionedRecyclerView<Ord
holder.mBinding.checkbox.jumpDrawablesToCurrentState();
listModel.getSelectedObservable().addOnPropertyChangedCallback(() -> {
if(this.mOnItemChecked != null) this.mOnItemChecked.run(listModel);
if (this.mOnItemChecked != null) this.mOnItemChecked.run(listModel);
});
holder.mBinding.getRoot().setOnClickListener(v -> {
listModel.getSelectedObservable().set(!listModel.getSelectedObservable().get());
});
}
@Override
public boolean onPlaceSubheaderBetweenItems(int position) {
if (getItemSize() == 1) return true;
else if (getItemSize() > 1) {
OrdiniUscitaElencoListModel compare1 = this.mDataset.get(position);
OrdiniUscitaElencoListModel compare2 = this.mDataset.get(position + 1);
return !UtilityString.equalsIgnoreCase(compare1.getGroupTitle(), compare2.getGroupTitle());
}
return true;
}
}

View File

@ -1,101 +1,94 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<import type="it.integry.integrywmsnative.core.di.BindableBoolean" />
<variable
name="selected"
type="BindableBoolean" />
</data>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
<!-- 1. Sostituito LinearLayout con ConstraintLayout per layout piatto -->
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="2dp"
android:paddingEnd="4dp"
android:paddingVertical="2dp"
android:orientation="horizontal">
<View
android:id="@+id/empty_view"
android:layout_width="8dp"
android:layout_height="match_parent" />
<LinearLayout
android:id="@+id/ordine_lavorazione_main_list_group_item_container_root"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical"
android:paddingStart="2dp"
android:paddingEnd="8dp"
android:paddingStart="4dp"
android:paddingEnd="12dp"
android:paddingVertical="4dp"
android:background="@color/full_white">
<!-- 2. Lo spazio di 8dp è ora gestito con constraint -->
<View
android:id="@+id/empty_view"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintWidth="8dp"/>
<!-- 3. CheckBox direttamente nel layout principale -->
<CheckBox
android:id="@+id/checkbox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:checked="@{selected}" />
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true">
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/right_descrizione"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="Cons 07 nov 2018"
android:layout_alignParentEnd="true"
android:textColor="#000"
style="@style/AppTheme.NewMaterial.Text.Small" />
app:checked="@{selected}"
app:layout_constraintStart_toEndOf="@id/empty_view"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent" />
<!-- 4. Descrizione principale a destra del checkbox -->
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/descrizione"
android:layout_width="wrap_content"
android:layout_width="0dp"
android:layout_height="wrap_content"
tools:text="Ord. Ven. 39 del 27 ott 2017"
android:ellipsize="end"
android:maxLines="1"
android:textColor="#000"
android:layout_alignParentStart="true"
style="@style/AppTheme.NewMaterial.Text.Small"
android:layout_toStartOf="@id/descrizione"/>
app:layout_constraintStart_toEndOf="@id/checkbox"
app:layout_constraintEnd_toStartOf="@id/right_descrizione"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"/>
<!-- 5. Descrizione secondaria a destra del checkbox, sotto la principale -->
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/sub_descrizione"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:maxLines="1"
android:ellipsize="end"
tools:text="TextView"
style="@style/AppTheme.NewMaterial.Text.Small"
app:layout_constraintStart_toStartOf="@id/descrizione"
app:layout_constraintEnd_toStartOf="@id/right_sub_descrizione"
app:layout_constraintTop_toBottomOf="@+id/descrizione"
android:layout_marginEnd="8dp"/>
<!-- 6. Right descrizione allineata a destra -->
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/right_descrizione"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="Cons 07 nov 2018"
android:textColor="#000"
style="@style/AppTheme.NewMaterial.Text.Small"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBaseline_toBaselineOf="@id/descrizione" />
<!-- 7. Right sub-descrizione allineata a destra -->
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/right_sub_descrizione"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="Cod Jcom"
android:layout_alignParentEnd="true"
android:layout_below="@id/descrizione"
style="@style/AppTheme.NewMaterial.Text.Small" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/sub_descrizione"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:maxLines="1"
android:ellipsize="end"
android:paddingEnd="6dp"
tools:text="TextView"
style="@style/AppTheme.NewMaterial.Text.Small"
android:layout_below="@+id/descrizione"
android:layout_toStartOf="@id/right_sub_descrizione"/>
</RelativeLayout>
</LinearLayout>
</LinearLayout>
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/right_descrizione"
app:layout_constraintBaseline_toBaselineOf="@id/sub_descrizione" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

View File

@ -1,5 +1,5 @@
<layout>
<androidx.appcompat.widget.LinearLayoutCompat
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@ -19,7 +19,7 @@
android:clickable="false"
android:enabled="false"/>
<androidx.appcompat.widget.AppCompatTextView
<TextView
android:id="@+id/group_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@ -29,6 +29,6 @@
style="@style/TextAppearance.Material3.TitleMedium"
tools:text="NOME GRUPPO"/>
</androidx.appcompat.widget.LinearLayoutCompat>
</LinearLayout>
</layout>