Migliorato adapter avantielenco ordini di uscita
This commit is contained in:
parent
6c59e22101
commit
706878b1e4
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -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<>() {{
|
||||
put("cod_jcom", x);
|
||||
}};
|
||||
return codJcom;
|
||||
})
|
||||
.map(x -> new HashMap<String, Object>() {{
|
||||
put("cod_jcom", x);
|
||||
}})
|
||||
.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);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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,71 +227,70 @@ 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)
|
||||
.setOnGroupItemClicked(x -> {
|
||||
if (!canSelectMultipleClienti) {
|
||||
Stream.of(mOrdiniInevasiMutableData)
|
||||
.filter(y -> !y.getGroupTitle().equalsIgnoreCase(x) && y.getSelectedObservable().get())
|
||||
.forEach(y -> y.getSelectedObservable().set(false));
|
||||
}
|
||||
|
||||
boolean allSelected = Stream.of(mOrdiniInevasiMutableData)
|
||||
.filter(y -> y.getGroupTitle().equalsIgnoreCase(x))
|
||||
.allMatch(y -> y.getSelectedObservable().get());
|
||||
|
||||
Stream.of(mOrdiniInevasiMutableData)
|
||||
.filter(y -> y.getGroupTitle().equalsIgnoreCase(x))
|
||||
.forEach(y -> y.getSelectedObservable().set(!allSelected));
|
||||
})
|
||||
.setOnItemChecked(x -> {
|
||||
if (!canSelectMultipleClienti && x.getSelectedObservable().get()) {
|
||||
Stream.of(mOrdiniInevasiMutableData)
|
||||
.filter(y -> !y.getGroupTitle().equalsIgnoreCase(x.getGroupTitle()) && y.getSelectedObservable().get())
|
||||
.forEach(y -> y.getSelectedObservable().set(false));
|
||||
}
|
||||
|
||||
fabVisible.set(Stream.of(mOrdiniInevasiMutableData)
|
||||
.anyMatch(y -> y.getSelectedObservable().get()));
|
||||
});
|
||||
|
||||
ordiniUscitaElencoAdapter
|
||||
.setEmptyView(this.mBindings.ordiniVenditaEmptyView);
|
||||
|
||||
this.mBindings.venditaMainList.setLayoutManager(new LinearLayoutManager(getActivity()));
|
||||
this.mBindings.venditaMainList.setItemViewCacheSize(20);
|
||||
this.mBindings.venditaMainList.setAdapter(ordiniUscitaElencoAdapter);
|
||||
|
||||
});
|
||||
|
||||
OrdiniUscitaElencoAdapter ordiniUscitaElencoAdapter =
|
||||
new OrdiniUscitaElencoAdapter(getActivity(), mOrdiniInevasiMutableData)
|
||||
.setOnGroupItemClicked(x -> {
|
||||
if (!canSelectMultipleClienti) {
|
||||
Stream.of(mOrdiniInevasiMutableData)
|
||||
.filter(y -> !y.getGroupTitle().equalsIgnoreCase(x) && y.getSelectedObservable().get())
|
||||
.forEach(y -> y.getSelectedObservable().set(false));
|
||||
}
|
||||
|
||||
boolean allSelected = Stream.of(mOrdiniInevasiMutableData)
|
||||
.filter(y -> y.getGroupTitle().equalsIgnoreCase(x))
|
||||
.allMatch(y -> y.getSelectedObservable().get());
|
||||
|
||||
Stream.of(mOrdiniInevasiMutableData)
|
||||
.filter(y -> y.getGroupTitle().equalsIgnoreCase(x))
|
||||
.forEach(y -> y.getSelectedObservable().set(!allSelected));
|
||||
})
|
||||
.setOnItemChecked(x -> {
|
||||
if (!canSelectMultipleClienti && x.getSelectedObservable().get()) {
|
||||
Stream.of(mOrdiniInevasiMutableData)
|
||||
.filter(y -> !y.getGroupTitle().equalsIgnoreCase(x.getGroupTitle()) && y.getSelectedObservable().get())
|
||||
.forEach(y -> y.getSelectedObservable().set(false));
|
||||
}
|
||||
|
||||
fabVisible.set(Stream.of(mOrdiniInevasiMutableData)
|
||||
.anyMatch(y -> y.getSelectedObservable().get()));
|
||||
});
|
||||
|
||||
ordiniUscitaElencoAdapter
|
||||
.setEmptyView(this.mBindings.ordiniVenditaEmptyView);
|
||||
|
||||
this.mBindings.venditaMainList.setAdapter(ordiniUscitaElencoAdapter);
|
||||
this.mBindings.venditaMainList.setLayoutManager(new LinearLayoutManager(getActivity()));
|
||||
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,21 +742,21 @@ public class OrdiniUscitaElencoFragment extends BaseFragment implements ITitledF
|
||||
this.mViewModel.processBarcodeDTO(data, this::onLoadingEnded);
|
||||
};
|
||||
|
||||
private void refreshList(List<OrdiniUscitaElencoDTO> filteredList) {
|
||||
requireActivity().runOnUiThread(() -> {
|
||||
List<OrdiniUscitaElencoDTO> tmpList;
|
||||
private void refreshList(List<OrdiniUscitaElencoDTO> originalData, List<OrdiniUscitaElencoDTO> filteredList) {
|
||||
List<OrdiniUscitaElencoDTO> tmpList;
|
||||
|
||||
if (filteredList != null) {
|
||||
tmpList = filteredList;
|
||||
} else if (mAppliedFilterViewModel != null) {
|
||||
mAppliedFilterViewModel.applyAllTests();
|
||||
tmpList = mAppliedFilterViewModel.getMutableFilteredOrderList().getValue();
|
||||
} else {
|
||||
tmpList = mViewModel.getOrderList().getValue();
|
||||
}
|
||||
if (filteredList != null) {
|
||||
tmpList = filteredList;
|
||||
} else if (mAppliedFilterViewModel != null) {
|
||||
mAppliedFilterViewModel.applyAllTests();
|
||||
tmpList = mAppliedFilterViewModel.getMutableFilteredOrderList().getValue();
|
||||
} else {
|
||||
tmpList = originalData;
|
||||
}
|
||||
|
||||
var list = convertDataModelToListModel(tmpList);
|
||||
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 -> {
|
||||
this.mtbDepoCache = mtbDepos;
|
||||
onComplete.run();
|
||||
}, this::onError);
|
||||
private void initMtbDepoCache() throws Exception {
|
||||
var mtbDepos = this.mDepositoRESTConsumer.getAllSynchronized();
|
||||
this.mtbDepoCache = mtbDepos;
|
||||
}
|
||||
|
||||
|
||||
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 -> {
|
||||
this.mtbGrupCache = mtbGrupCache;
|
||||
onComplete.run();
|
||||
}, this::onError);
|
||||
var mtbGrupCache = this.mArticoloRESTConsumer.getArtsGroupsSynchronized(codMgrpArts);
|
||||
this.mtbGrupCache = mtbGrupCache;
|
||||
}
|
||||
|
||||
|
||||
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 -> {
|
||||
this.jtbComtCache = jtbComtCache;
|
||||
onComplete.run();
|
||||
}, this::onError);
|
||||
var jtbComtCache = this.mCommessaRESTConsumer.getJtbComtsSynchronized(jtbComts);
|
||||
this.jtbComtCache = jtbComtCache;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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,39 +59,37 @@ 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)
|
||||
.map(x -> {
|
||||
try {
|
||||
return OrdiniUscitaElencoDTO.fromParent(x);
|
||||
} catch (Exception ex) {
|
||||
return null;
|
||||
}
|
||||
})
|
||||
.toList());
|
||||
|
||||
long forcedDelaySecs = (new Date().getTime() - loadingStartDate.getTime()) / 1000;
|
||||
|
||||
if (2 - forcedDelaySecs > 0) {
|
||||
try {
|
||||
Thread.sleep((2 - forcedDelaySecs) * 1000);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
var orderList = ordiniLavorazione.parallelStream()
|
||||
.map(x -> {
|
||||
try {
|
||||
return OrdiniUscitaElencoDTO.fromParent(x);
|
||||
} catch (Exception ex) {
|
||||
return null;
|
||||
}
|
||||
})
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
this.sendOnLoadingEnded();
|
||||
}, this::sendError);
|
||||
this.mOrderList.postValue(orderList);
|
||||
|
||||
// long forcedDelaySecs = (new Date().getTime() - loadingStartDate.getTime()) / 1000;
|
||||
//
|
||||
// if (2 - forcedDelaySecs > 0) {
|
||||
// try {
|
||||
// Thread.sleep((2 - forcedDelaySecs) * 1000);
|
||||
// } catch (Exception ignored) {
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -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() {
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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">
|
||||
|
||||
|
||||
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="8dp"
|
||||
android:layout_height="match_parent" />
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintWidth="8dp"/>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/ordine_lavorazione_main_list_group_item_container_root"
|
||||
android:layout_width="match_parent"
|
||||
<!-- 3. CheckBox direttamente nel layout principale -->
|
||||
<CheckBox
|
||||
android:id="@+id/checkbox"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingStart="2dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:background="@color/full_white">
|
||||
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="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
tools:text="Ord. Ven. 39 del 27 ott 2017"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textColor="#000"
|
||||
style="@style/AppTheme.NewMaterial.Text.Small"
|
||||
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"/>
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/checkbox"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:checked="@{selected}" />
|
||||
<!-- 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"/>
|
||||
|
||||
<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" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/descrizione"
|
||||
android:layout_width="wrap_content"
|
||||
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"/>
|
||||
|
||||
|
||||
<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>
|
||||
<!-- 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"
|
||||
style="@style/AppTheme.NewMaterial.Text.Small"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/right_descrizione"
|
||||
app:layout_constraintBaseline_toBaselineOf="@id/sub_descrizione" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</layout>
|
||||
@ -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>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user