From 1acdd3f08d86e58b23e4ca5e391c18443348f617 Mon Sep 17 00:00:00 2001 From: prada Date: Sat, 12 Sep 2026 17:02:24 +0100 Subject: [PATCH] Convert Android sources to Kotlin --- .../infinitescroll/InfiniteScrollAdapter.java | 194 ------------------ .../infinitescroll/InfiniteScrollAdapter.kt | 156 ++++++++++++++ .../sample/DemoGridActivity.java | 45 ---- .../sample/DemoListActivity.java | 49 ----- .../infinitescroll/sample/MainActivity.java | 33 --- .../infinitescroll/sample/SampleAdapter.java | 44 ---- .../infinitescroll/sample/DemoGridActivity.kt | 45 ++++ .../infinitescroll/sample/DemoListActivity.kt | 40 ++++ .../ui/infinitescroll/sample/MainActivity.kt | 21 ++ .../ui/infinitescroll/sample/SampleAdapter.kt | 27 +++ 10 files changed, 289 insertions(+), 365 deletions(-) delete mode 100644 library/src/main/java/lab/prada/android/ui/lab/prada/android/ui/infinitescroll/InfiniteScrollAdapter.java create mode 100644 library/src/main/kotlin/lab/prada/android/ui/lab/prada/android/ui/infinitescroll/InfiniteScrollAdapter.kt delete mode 100644 sample/src/main/java/lab/prada/android/ui/infinitescroll/sample/DemoGridActivity.java delete mode 100644 sample/src/main/java/lab/prada/android/ui/infinitescroll/sample/DemoListActivity.java delete mode 100644 sample/src/main/java/lab/prada/android/ui/infinitescroll/sample/MainActivity.java delete mode 100644 sample/src/main/java/lab/prada/android/ui/infinitescroll/sample/SampleAdapter.java create mode 100644 sample/src/main/kotlin/lab/prada/android/ui/infinitescroll/sample/DemoGridActivity.kt create mode 100644 sample/src/main/kotlin/lab/prada/android/ui/infinitescroll/sample/DemoListActivity.kt create mode 100644 sample/src/main/kotlin/lab/prada/android/ui/infinitescroll/sample/MainActivity.kt create mode 100644 sample/src/main/kotlin/lab/prada/android/ui/infinitescroll/sample/SampleAdapter.kt diff --git a/library/src/main/java/lab/prada/android/ui/lab/prada/android/ui/infinitescroll/InfiniteScrollAdapter.java b/library/src/main/java/lab/prada/android/ui/lab/prada/android/ui/infinitescroll/InfiniteScrollAdapter.java deleted file mode 100644 index f0bfcdd..0000000 --- a/library/src/main/java/lab/prada/android/ui/lab/prada/android/ui/infinitescroll/InfiniteScrollAdapter.java +++ /dev/null @@ -1,194 +0,0 @@ -package lab.prada.android.ui.lab.prada.android.ui.infinitescroll; - -import android.content.Context; -import android.database.DataSetObserver; -import android.os.Looper; -import android.view.Gravity; -import android.view.View; -import android.view.ViewGroup; -import android.widget.Adapter; -import android.widget.BaseAdapter; -import android.widget.GridView; -import android.widget.ProgressBar; -import android.widget.RelativeLayout; - -import java.util.Vector; -import java.util.concurrent.atomic.AtomicInteger; - -public class InfiniteScrollAdapter extends BaseAdapter { - - private final T mAdapter; - private final View mProgressView; - private Vector mListeners = new Vector(); - - private final static int NONE_STATE = 0; - private final static int REFRESHING_STATE = 1; - private AtomicInteger state = new AtomicInteger(NONE_STATE); - private boolean mCanReadMore = true; - - public interface InfiniteScrollListener { - public void onInfiniteScrolled(); - } - - public InfiniteScrollAdapter(Context context, T adapter, View progressView) { - mAdapter = adapter; - mProgressView = progressView; - } - - public InfiniteScrollAdapter(Context context, T adapter, int itemWidth, - int itemHeight) { - mAdapter = adapter; - RelativeLayout layout = new RelativeLayout(context); - layout.setLayoutParams(new GridView.LayoutParams(itemWidth, - itemHeight)); - layout.setGravity(Gravity.CENTER); - layout.addView(new ProgressBar(context)); - - mProgressView = layout; - } - - public InfiniteScrollAdapter(T adapter, View progressView) { - mAdapter = adapter; - mProgressView = progressView; - } - - @Override - public boolean areAllItemsEnabled() { - return mAdapter.areAllItemsEnabled(); - } - - @Override - public View getDropDownView(int position, View convertView, ViewGroup parent) { - return (isProgressViewPosition(position)) ? null : mAdapter - .getDropDownView(position, convertView, parent); - } - - @Override - public int getItemViewType(int position) { - return (isProgressViewPosition(position)) ? Adapter.IGNORE_ITEM_VIEW_TYPE - : mAdapter.getItemViewType(position); - } - - @Override - public int getViewTypeCount() { - return mAdapter.getViewTypeCount(); - } - - @Override - public boolean hasStableIds() { - return mAdapter.hasStableIds(); - } - - @Override - public boolean isEmpty() { - return mAdapter.isEmpty(); - } - - @Override - public boolean isEnabled(int position) { - return (isProgressViewPosition(position)) ? false : mAdapter - .isEnabled(position); - } - - @Override - public void notifyDataSetChanged() { - mAdapter.notifyDataSetChanged(); - } - - @Override - public void notifyDataSetInvalidated() { - mAdapter.notifyDataSetInvalidated(); - } - - @Override - public void registerDataSetObserver(DataSetObserver observer) { - mAdapter.registerDataSetObserver(observer); - } - - @Override - public void unregisterDataSetObserver(DataSetObserver observer) { - mAdapter.unregisterDataSetObserver(observer); - } - - @Override - public int getCount() { - return shouldShowProgressView() ? mAdapter.getCount() + 1 : mAdapter - .getCount(); - } - - @Override - public Object getItem(int position) { - return (isProgressViewPosition(position)) ? null : mAdapter - .getItem(position); - } - - @Override - public long getItemId(int position) { - return (isProgressViewPosition(position)) ? -1 : mAdapter - .getItemId(position); - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - if (isProgressViewPosition(position)) { - if (isRefreshing() == false) { - state.set(REFRESHING_STATE); - if (mListeners != null) { - for (InfiniteScrollListener listener : mListeners) { - listener.onInfiniteScrolled(); - } - } - } - if (mProgressView.getVisibility() == View.GONE) { - mProgressView.setVisibility(View.VISIBLE); - } - return mProgressView; - } else { - return mAdapter.getView(position, convertView, parent); - } - } - - public T getOriginalAdapter() { - return mAdapter; - } - - public void removeListener(InfiniteScrollListener listener) { - if (listener != null) { - mListeners.remove(listener); - } - } - - public void addListener(InfiniteScrollListener listener) { - if (listener != null && mListeners.contains(listener) == false) { - mListeners.add(listener); - } - } - - public boolean isProgressViewPosition(int position) { - return shouldShowProgressView() && position == getCount() - 1; - } - - private boolean shouldShowProgressView() { - return mAdapter.getCount() > 0 && mCanReadMore; - } - - public void canReadMore(boolean enable) { - mCanReadMore = enable; - } - - public boolean isRefreshing() { - return state.get() == REFRESHING_STATE; - } - - public void handledRefresh() { - assert(Looper.myLooper().equals(Looper.getMainLooper())); - if (isRefreshing()) { - mProgressView.setVisibility(View.GONE); - state.set(NONE_STATE); - } - } - - public T getAdapter() { - return mAdapter; - } -} diff --git a/library/src/main/kotlin/lab/prada/android/ui/lab/prada/android/ui/infinitescroll/InfiniteScrollAdapter.kt b/library/src/main/kotlin/lab/prada/android/ui/lab/prada/android/ui/infinitescroll/InfiniteScrollAdapter.kt new file mode 100644 index 0000000..20ae808 --- /dev/null +++ b/library/src/main/kotlin/lab/prada/android/ui/lab/prada/android/ui/infinitescroll/InfiniteScrollAdapter.kt @@ -0,0 +1,156 @@ +package lab.prada.android.ui.lab.prada.android.ui.infinitescroll + +import android.content.Context +import android.database.DataSetObserver +import android.os.Looper +import android.view.Gravity +import android.view.View +import android.view.ViewGroup +import android.widget.Adapter +import android.widget.AbsListView +import android.widget.BaseAdapter +import android.widget.ProgressBar +import android.widget.RelativeLayout +import java.util.concurrent.CopyOnWriteArrayList +import java.util.concurrent.atomic.AtomicInteger + +/** Adds a progress row to a [BaseAdapter] and notifies listeners when it is displayed. */ +class InfiniteScrollAdapter : BaseAdapter { + private val adapter: T + private val progressView: View + private val listeners = CopyOnWriteArrayList() + private val state = AtomicInteger(NONE_STATE) + + @Volatile + private var canReadMoreEnabled = true + + interface InfiniteScrollListener { + fun onInfiniteScrolled() + } + + constructor(context: Context, adapter: T, progressView: View) { + this.adapter = adapter + this.progressView = progressView + } + + constructor(context: Context, adapter: T, itemWidth: Int, itemHeight: Int) { + this.adapter = adapter + this.progressView = RelativeLayout(context).apply { + layoutParams = AbsListView.LayoutParams(itemWidth, itemHeight) + gravity = Gravity.CENTER + addView(ProgressBar(context)) + } + } + + constructor(adapter: T, progressView: View) { + this.adapter = adapter + this.progressView = progressView + } + + override fun areAllItemsEnabled(): Boolean = adapter.areAllItemsEnabled() + + override fun getDropDownView( + position: Int, + convertView: View?, + parent: ViewGroup + ): View? = if (isProgressViewPosition(position)) { + null + } else { + adapter.getDropDownView(position, convertView, parent) + } + + override fun getItemViewType(position: Int): Int = if (isProgressViewPosition(position)) { + Adapter.IGNORE_ITEM_VIEW_TYPE + } else { + adapter.getItemViewType(position) + } + + override fun getViewTypeCount(): Int = adapter.viewTypeCount + + override fun hasStableIds(): Boolean = adapter.hasStableIds() + + override fun isEmpty(): Boolean = adapter.isEmpty + + override fun registerDataSetObserver(observer: DataSetObserver) { + adapter.registerDataSetObserver(observer) + } + + override fun unregisterDataSetObserver(observer: DataSetObserver) { + adapter.unregisterDataSetObserver(observer) + } + + override fun getCount(): Int = if (shouldShowProgressView()) { + adapter.count + 1 + } else { + adapter.count + } + + override fun getItem(position: Int): Any? = if (isProgressViewPosition(position)) { + null + } else { + adapter.getItem(position) + } + + override fun getItemId(position: Int): Long = if (isProgressViewPosition(position)) { + -1L + } else { + adapter.getItemId(position) + } + + override fun getView(position: Int, convertView: View?, parent: ViewGroup): View { + if (!isProgressViewPosition(position)) { + return adapter.getView(position, convertView, parent) + } + + if (state.compareAndSet(NONE_STATE, REFRESHING_STATE)) { + listeners.forEach(InfiniteScrollListener::onInfiniteScrolled) + } + + if (progressView.visibility == View.GONE) { + progressView.visibility = View.VISIBLE + } + return progressView + } + + fun removeListener(listener: InfiniteScrollListener?) { + if (listener != null) { + listeners.remove(listener) + } + } + + fun addListener(listener: InfiniteScrollListener?) { + if (listener != null) { + listeners.addIfAbsent(listener) + } + } + + fun isProgressViewPosition(position: Int): Boolean = + shouldShowProgressView() && position == count - 1 + + fun canReadMore(enable: Boolean) { + canReadMoreEnabled = enable + notifyDataSetChanged() + } + + fun isRefreshing(): Boolean = state.get() == REFRESHING_STATE + + fun handledRefresh() { + check(Looper.myLooper() == Looper.getMainLooper()) { + "handledRefresh() must be called on the main thread" + } + if (state.compareAndSet(REFRESHING_STATE, NONE_STATE)) { + progressView.visibility = View.GONE + } + } + + fun getOriginalAdapter(): T = adapter + + fun getAdapter(): T = adapter + + private fun shouldShowProgressView(): Boolean = adapter.count > 0 && canReadMoreEnabled + + private companion object { + const val NONE_STATE = 0 + const val REFRESHING_STATE = 1 + } +} diff --git a/sample/src/main/java/lab/prada/android/ui/infinitescroll/sample/DemoGridActivity.java b/sample/src/main/java/lab/prada/android/ui/infinitescroll/sample/DemoGridActivity.java deleted file mode 100644 index 2c86cad..0000000 --- a/sample/src/main/java/lab/prada/android/ui/infinitescroll/sample/DemoGridActivity.java +++ /dev/null @@ -1,45 +0,0 @@ -package lab.prada.android.ui.infinitescroll.sample; - -import android.app.Activity; -import android.os.Bundle; -import android.os.Handler; -import android.os.Looper; -import android.widget.GridView; - -import lab.prada.android.ui.lab.prada.android.ui.infinitescroll.InfiniteScrollAdapter; -import lab.prada.android.ui.mymodule.app.R; - -public class DemoGridActivity extends Activity implements InfiniteScrollAdapter.InfiniteScrollListener { - - private static final int GRID_ITEM_HEIGHT = 128; - private static final int GRID_ITEM_WIDTH = 128; - private GridView mGridView; - private InfiniteScrollAdapter mAdapter; - private Handler mHandler; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_demo_grid); - mGridView = (GridView) findViewById(R.id.gridView1); - mAdapter = new InfiniteScrollAdapter(this, - new SampleAdapter(this), GRID_ITEM_WIDTH, GRID_ITEM_HEIGHT); - mAdapter.addListener(this); - mGridView.setAdapter(mAdapter); - mHandler = new Handler(Looper.getMainLooper()); - } - - @Override - public void onInfiniteScrolled() { - mHandler.postDelayed(new Runnable() { - @Override - public void run() { - mAdapter.getAdapter().addCount(5); - mAdapter.handledRefresh(); - if (mAdapter.getOriginalAdapter().getCount() > 100) { - mAdapter.canReadMore(false); - } - } - }, 3000); - } -} diff --git a/sample/src/main/java/lab/prada/android/ui/infinitescroll/sample/DemoListActivity.java b/sample/src/main/java/lab/prada/android/ui/infinitescroll/sample/DemoListActivity.java deleted file mode 100644 index f6e8795..0000000 --- a/sample/src/main/java/lab/prada/android/ui/infinitescroll/sample/DemoListActivity.java +++ /dev/null @@ -1,49 +0,0 @@ -package lab.prada.android.ui.infinitescroll.sample; - -import android.app.Activity; -import android.os.Bundle; -import android.os.Handler; -import android.os.Looper; -import android.view.Gravity; -import android.widget.GridView; -import android.widget.ListView; -import android.widget.ProgressBar; -import android.widget.RelativeLayout; - -import lab.prada.android.ui.lab.prada.android.ui.infinitescroll.InfiniteScrollAdapter; -import lab.prada.android.ui.mymodule.app.R; - -public class DemoListActivity extends Activity implements InfiniteScrollAdapter.InfiniteScrollListener { - - private InfiniteScrollAdapter mAdapter; - private Handler mHandler; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_demo_list); - - RelativeLayout progress = new RelativeLayout(this); - progress.setLayoutParams(new GridView.LayoutParams( - GridView.LayoutParams.MATCH_PARENT, 100)); - progress.setGravity(Gravity.CENTER); - progress.addView(new ProgressBar(this)); - - mAdapter = new InfiniteScrollAdapter(this, - new SampleAdapter(this), progress); - mAdapter.addListener(this); - mHandler = new Handler(Looper.getMainLooper()); - ((ListView) findViewById(R.id.listView)).setAdapter(mAdapter); - } - - @Override - public void onInfiniteScrolled() { - mHandler.postDelayed(new Runnable() { - @Override - public void run() { - mAdapter.getAdapter().addCount(5); - mAdapter.handledRefresh(); - } - }, 3000); - } -} diff --git a/sample/src/main/java/lab/prada/android/ui/infinitescroll/sample/MainActivity.java b/sample/src/main/java/lab/prada/android/ui/infinitescroll/sample/MainActivity.java deleted file mode 100644 index fdc0c4e..0000000 --- a/sample/src/main/java/lab/prada/android/ui/infinitescroll/sample/MainActivity.java +++ /dev/null @@ -1,33 +0,0 @@ -package lab.prada.android.ui.infinitescroll.sample; - -import android.app.Activity; -import android.content.Intent; -import android.os.Bundle; -import android.view.View; -import android.view.View.OnClickListener; - -import lab.prada.android.ui.mymodule.app.R; - -public class MainActivity extends Activity { - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.main); - findViewById(R.id.button1).setOnClickListener(new OnClickListener() { - @Override - public void onClick(View arg0) { - Intent intent = new Intent(MainActivity.this, - DemoListActivity.class); - startActivity(intent); - } - }); - findViewById(R.id.button2).setOnClickListener(new OnClickListener() { - @Override - public void onClick(View arg0) { - Intent intent = new Intent(MainActivity.this, - DemoGridActivity.class); - startActivity(intent); - } - }); - } -} diff --git a/sample/src/main/java/lab/prada/android/ui/infinitescroll/sample/SampleAdapter.java b/sample/src/main/java/lab/prada/android/ui/infinitescroll/sample/SampleAdapter.java deleted file mode 100644 index e9ee712..0000000 --- a/sample/src/main/java/lab/prada/android/ui/infinitescroll/sample/SampleAdapter.java +++ /dev/null @@ -1,44 +0,0 @@ -package lab.prada.android.ui.infinitescroll.sample; - -import android.content.Context; -import android.view.View; -import android.view.ViewGroup; -import android.widget.BaseAdapter; -import android.widget.Button; - -public class SampleAdapter extends BaseAdapter { - private Context mContext; - private int count = 50; - - public SampleAdapter(Context context) { - mContext = context; - } - - @Override - public int getCount() { - return count; - } - - public void addCount(int num) { - count += num; - notifyDataSetChanged(); - } - - @Override - public Object getItem(int arg0) { - return arg0; - } - - @Override - public long getItemId(int arg0) { - return arg0; - } - - @Override - public View getView(int arg0, View arg1, ViewGroup arg2) { - Button btn = new Button(mContext); - btn.setText("button " + arg0); - return btn; - } - -} \ No newline at end of file diff --git a/sample/src/main/kotlin/lab/prada/android/ui/infinitescroll/sample/DemoGridActivity.kt b/sample/src/main/kotlin/lab/prada/android/ui/infinitescroll/sample/DemoGridActivity.kt new file mode 100644 index 0000000..171c7db --- /dev/null +++ b/sample/src/main/kotlin/lab/prada/android/ui/infinitescroll/sample/DemoGridActivity.kt @@ -0,0 +1,45 @@ +package lab.prada.android.ui.infinitescroll.sample + +import android.app.Activity +import android.os.Bundle +import android.os.Handler +import android.os.Looper +import android.widget.GridView +import lab.prada.android.ui.lab.prada.android.ui.infinitescroll.InfiniteScrollAdapter +import lab.prada.android.ui.mymodule.app.R + +class DemoGridActivity : Activity(), InfiniteScrollAdapter.InfiniteScrollListener { + private companion object { + const val GRID_ITEM_HEIGHT = 128 + const val GRID_ITEM_WIDTH = 128 + } + + private lateinit var gridView: GridView + private lateinit var adapter: InfiniteScrollAdapter + private val handler = Handler(Looper.getMainLooper()) + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_demo_grid) + + gridView = findViewById(R.id.gridView1) + adapter = InfiniteScrollAdapter( + this, + SampleAdapter(this), + GRID_ITEM_WIDTH, + GRID_ITEM_HEIGHT + ) + adapter.addListener(this) + gridView.adapter = adapter + } + + override fun onInfiniteScrolled() { + handler.postDelayed({ + adapter.getOriginalAdapter().addCount(5) + adapter.handledRefresh() + if (adapter.getOriginalAdapter().count >= 100) { + adapter.canReadMore(false) + } + }, 3000) + } +} diff --git a/sample/src/main/kotlin/lab/prada/android/ui/infinitescroll/sample/DemoListActivity.kt b/sample/src/main/kotlin/lab/prada/android/ui/infinitescroll/sample/DemoListActivity.kt new file mode 100644 index 0000000..a5d805f --- /dev/null +++ b/sample/src/main/kotlin/lab/prada/android/ui/infinitescroll/sample/DemoListActivity.kt @@ -0,0 +1,40 @@ +package lab.prada.android.ui.infinitescroll.sample + +import android.app.Activity +import android.os.Bundle +import android.os.Handler +import android.os.Looper +import android.view.Gravity +import android.widget.AbsListView +import android.widget.ListView +import android.widget.ProgressBar +import android.widget.RelativeLayout +import lab.prada.android.ui.lab.prada.android.ui.infinitescroll.InfiniteScrollAdapter +import lab.prada.android.ui.mymodule.app.R + +class DemoListActivity : Activity(), InfiniteScrollAdapter.InfiniteScrollListener { + private lateinit var adapter: InfiniteScrollAdapter + private val handler = Handler(Looper.getMainLooper()) + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_demo_list) + + val progress = RelativeLayout(this).apply { + layoutParams = AbsListView.LayoutParams(AbsListView.LayoutParams.MATCH_PARENT, 100) + gravity = Gravity.CENTER + addView(ProgressBar(this@DemoListActivity)) + } + + adapter = InfiniteScrollAdapter(this, SampleAdapter(this), progress) + adapter.addListener(this) + findViewById(R.id.listView).adapter = adapter + } + + override fun onInfiniteScrolled() { + handler.postDelayed({ + adapter.getOriginalAdapter().addCount(5) + adapter.handledRefresh() + }, 3000) + } +} diff --git a/sample/src/main/kotlin/lab/prada/android/ui/infinitescroll/sample/MainActivity.kt b/sample/src/main/kotlin/lab/prada/android/ui/infinitescroll/sample/MainActivity.kt new file mode 100644 index 0000000..fc61f0a --- /dev/null +++ b/sample/src/main/kotlin/lab/prada/android/ui/infinitescroll/sample/MainActivity.kt @@ -0,0 +1,21 @@ +package lab.prada.android.ui.infinitescroll.sample + +import android.app.Activity +import android.content.Intent +import android.os.Bundle +import android.view.View +import lab.prada.android.ui.mymodule.app.R + +class MainActivity : Activity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.main) + + findViewById(R.id.button1).setOnClickListener { + startActivity(Intent(this, DemoListActivity::class.java)) + } + findViewById(R.id.button2).setOnClickListener { + startActivity(Intent(this, DemoGridActivity::class.java)) + } + } +} diff --git a/sample/src/main/kotlin/lab/prada/android/ui/infinitescroll/sample/SampleAdapter.kt b/sample/src/main/kotlin/lab/prada/android/ui/infinitescroll/sample/SampleAdapter.kt new file mode 100644 index 0000000..823a09c --- /dev/null +++ b/sample/src/main/kotlin/lab/prada/android/ui/infinitescroll/sample/SampleAdapter.kt @@ -0,0 +1,27 @@ +package lab.prada.android.ui.infinitescroll.sample + +import android.content.Context +import android.view.View +import android.view.ViewGroup +import android.widget.BaseAdapter +import android.widget.Button + +class SampleAdapter(private val context: Context) : BaseAdapter() { + private var count = 50 + + override fun getCount(): Int = count + + fun addCount(number: Int) { + count += number + notifyDataSetChanged() + } + + override fun getItem(position: Int): Any = position + + override fun getItemId(position: Int): Long = position.toLong() + + override fun getView(position: Int, convertView: View?, parent: ViewGroup): View = + Button(context).apply { + text = "button $position" + } +}