From e07cb6909fbf049f7e45e566814e2c184eccf747 Mon Sep 17 00:00:00 2001 From: Jay Date: Thu, 6 Jul 2017 17:43:52 +0800 Subject: [PATCH] v1.0.1 release --- .idea/modules.xml | 1 + app/build.gradle | 15 +- app/src/main/AndroidManifest.xml | 5 +- .../main/java/xyz/mtfos/buywhat/ItemRandom.kt | 223 ++++++++++++++++++ .../java/xyz/mtfos/buywhat/SampleActivity.kt | 45 ++++ .../main/java/xyz/mtfos/buywhat/StoreList.kt | 27 ++- .../main/java/xyz/mtfos/tools/apiObject.kt | 2 +- .../ic_keyboard_arrow_left_black_24dp.png | Bin 0 -> 150 bytes .../ic_keyboard_arrow_left_black_24dp.png | Bin 0 -> 125 bytes .../ic_keyboard_arrow_left_black_24dp.png | Bin 0 -> 160 bytes .../ic_keyboard_arrow_left_black_24dp.png | Bin 0 -> 215 bytes .../ic_keyboard_arrow_left_black_24dp.png | Bin 0 -> 191 bytes app/src/main/res/drawable/logo.png | Bin 0 -> 12295 bytes .../main/res/layout/activity_item_random.xml | 166 +++++++++++++ .../main/res/layout/activity_store_list.xml | 106 +++++---- app/src/main/res/layout/lay_loading.xml | 13 + .../res/layout/listview_commodity_item.xml | 35 +++ app/src/main/res/values/size.xml | 4 + app/src/main/res/values/strings.xml | 7 +- build.gradle | 2 +- mtfos | Bin 0 -> 2216 bytes 21 files changed, 585 insertions(+), 66 deletions(-) create mode 100644 app/src/main/java/xyz/mtfos/buywhat/ItemRandom.kt create mode 100644 app/src/main/java/xyz/mtfos/buywhat/SampleActivity.kt create mode 100644 app/src/main/res/drawable-hdpi/ic_keyboard_arrow_left_black_24dp.png create mode 100644 app/src/main/res/drawable-mdpi/ic_keyboard_arrow_left_black_24dp.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_keyboard_arrow_left_black_24dp.png create mode 100644 app/src/main/res/drawable-xxhdpi/ic_keyboard_arrow_left_black_24dp.png create mode 100644 app/src/main/res/drawable-xxxhdpi/ic_keyboard_arrow_left_black_24dp.png create mode 100644 app/src/main/res/drawable/logo.png create mode 100644 app/src/main/res/layout/activity_item_random.xml create mode 100644 app/src/main/res/layout/lay_loading.xml create mode 100644 app/src/main/res/layout/listview_commodity_item.xml create mode 100644 app/src/main/res/values/size.xml create mode 100644 mtfos diff --git a/.idea/modules.xml b/.idea/modules.xml index 8d9fd1f..62cc6ac 100644 --- a/.idea/modules.xml +++ b/.idea/modules.xml @@ -2,6 +2,7 @@ + diff --git a/app/build.gradle b/app/build.gradle index f118913..8cd8421 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -11,14 +11,25 @@ android { applicationId "xyz.mtfos.buywhat" minSdkVersion 15 targetSdkVersion 26 - versionCode 1 - versionName "1.0" + versionCode 4 + versionName "1.0.1" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } + + signingConfigs { + release { + storeFile file("${rootDir}/mtfos") + storePassword "pass.ok=1" + keyAlias "mtfos" + keyPassword "pass.ok=1" + } + } + buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + signingConfig signingConfigs.release } } } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 45f0bf2..6b36685 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -6,9 +6,9 @@ @@ -19,6 +19,7 @@ + \ No newline at end of file diff --git a/app/src/main/java/xyz/mtfos/buywhat/ItemRandom.kt b/app/src/main/java/xyz/mtfos/buywhat/ItemRandom.kt new file mode 100644 index 0000000..00f1df5 --- /dev/null +++ b/app/src/main/java/xyz/mtfos/buywhat/ItemRandom.kt @@ -0,0 +1,223 @@ +package xyz.mtfos.buywhat + +import android.annotation.SuppressLint +import android.content.Context +import android.os.Bundle +import android.os.Handler +import android.os.Message +import android.view.View +import android.view.ViewGroup +import android.widget.* +import org.json.JSONArray +import org.json.JSONObject +import xyz.mtfos.tools.apiObject +import xyz.mtfos.tools.objectTool.bind +import java.util.* +import kotlin.collections.ArrayList + +/** + * Created by jay on 2017/7/6. + */ +class ItemRandom : SampleActivity() { + private val tvTitle: TextView by bind(R.id.tvTitle) + private val ivRefresh: ImageView by bind(R.id.ivRefresh) + private val lvCommodity: ListView by bind(R.id.lvCommodity) + private var store_id: Int? = null + private var itemList: ArrayList = ArrayList() + private var adapter: lvAdapter? = null + private val rangeMin: EditText by bind(R.id.rangeMin) + private val rangeMax: EditText by bind(R.id.rangeMax) + private val btnRandom: Button by bind(R.id.btnRandom) + private val tvResult: TextView by bind(R.id.tvResult) + private val ivBack: ImageView by bind(R.id.ivBack) + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setViewSource(R.layout.activity_item_random) + + tvTitle?.text = intent?.getStringExtra("name") + store_id = intent?.getIntExtra("id", 0) + + adapter = lvAdapter(this@ItemRandom, 0) + + lvCommodity.adapter = adapter + + lvCommodity.setOnItemClickListener({parent, view, position, id -> + val data: JSONObject = itemList.get(position) as JSONObject + var sk:Boolean = data!!["skip"] as Boolean + data?.put("skip", !sk) + itemList.set(position, data) + adapter?.notifyDataSetChanged() + + randomItem() + }) + + btnRandom.setOnClickListener{v-> + val json : JSONObject? = randomItem() + val str : String = if(json != null) { + "Result : ${json!!["name"]} $${json!!["price"]}" + }else{ + "Result : 目標區間無商品" + } + tvResult.text = str + } + + ivRefresh.setOnClickListener({ v -> + getList() + }) + + ivBack.setOnClickListener({ v -> + finish() + }) + + getList() + } + + fun getList() { + if(store_id == 0 || store_id == null) return + resetView() + toggleLoading(true) + api.getItems(store_id!!, object: apiObject.apicb{ + override fun Callback(json: JSONObject?) { + uiHandler.post { toggleLoading(false) } + if(json!!["status"] == 1) { + val jarr :JSONArray = json!!["record"] as JSONArray + itemList.clear() + if(jarr.length() > 0) { + uiHandler.sendEmptyMessage(3) + for(i in 0..(jarr.length() - 1)){ + val tmp: JSONObject =jarr!![i] as JSONObject + tmp.put("skip", false) + itemList.add(tmp) + } + }else{ + uiHandler.sendEmptyMessage(2) + } + uiHandler.sendEmptyMessage(1) + } + } + }) + } + + + fun resetView () { + rangeMin.setText("0") + rangeMax.setText("0") + tvResult.text = "" + } + + fun randomItem (): JSONObject? { + val min: String = rangeMin.text.toString() + val max: String = rangeMax.text.toString() + + var imin = if(min.toIntOrNull() == null) 0 else min.toInt() + var imax = if(max.toIntOrNull() == null) 0 else max.toInt() + + val tmp: ArrayList = ArrayList() + + for(i in 0..(itemList.size - 1)){ + val t:JSONObject = itemList[i] + var flag:Boolean = false + + val price:Int = t!!["price"] as Int + + if(t!!["skip"] == false){ + if(imin == 0 && imax == 0){ + flag = true + }else if(imin > 0 && imax == 0){ + if(price >= imin){ + flag = true + } + }else if(imin == 0 && imax > 0) { + if(price <= imax) { + flag = true + } + }else{ + if(price in imin..imax) { + flag = true + } + } + } + + if(flag){ + tmp.add(t) + } + } + + var arr: Array = tmp.toTypedArray() + + if(arr.isNotEmpty()) { + arr = shuffleArray(arr) as Array + } + + return if(arr.isNotEmpty()) { + arr[0] + } else { + null + } + } + + fun shuffleArray(arr: Array) : Array{ + var tmp = arr + + var rand: Random = Random() + + var limit: Int = 0 + while (limit < 2) { + for (i in 0..(tmp.size - 1)) { + val pos: Int = rand.nextInt(tmp.size) + val a = tmp[pos] + tmp[pos] = tmp[i] + tmp[i] = a + } + limit ++ + } + + return tmp + } + + @SuppressLint("HandlerLeak") + private val uiHandler = object : Handler() { + override fun handleMessage(msg: Message?) { + super.handleMessage(msg) + when (msg!!.what) { + 1 -> { + // update listview data + adapter!!.clear() + adapter!!.addAll(itemList) + } + 2 -> { + btnRandom.isClickable = false + } + 3 -> { + btnRandom.isClickable = true + } + } + } + } + + class lvAdapter(context: Context, resource: Int) : ArrayAdapter(context, resource) { + + override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View { + val data = getItem(position) as JSONObject + var v: View = if (convertView == null) { + View.inflate(context, R.layout.listview_commodity_item, null) + } else { + convertView + } + + val tvSkip: TextView = v.findViewById(R.id.tvSkip) + tvSkip.text = if(data!!["skip"] == false){ + context.getString(R.string.commodity_no_skip) + }else{ + context.getString(R.string.commodity_skip) + } + + val tv: TextView = v.findViewById(R.id.tvItem) + val name:String = data!!["name"] as String + val price:Int = data!!["price"] as Int + tv.text = "${name} $${price}" + return v + } + } +} \ No newline at end of file diff --git a/app/src/main/java/xyz/mtfos/buywhat/SampleActivity.kt b/app/src/main/java/xyz/mtfos/buywhat/SampleActivity.kt new file mode 100644 index 0000000..8295b4c --- /dev/null +++ b/app/src/main/java/xyz/mtfos/buywhat/SampleActivity.kt @@ -0,0 +1,45 @@ +package xyz.mtfos.buywhat + +import android.app.Activity +import android.os.Handler +import android.view.View +import android.view.ViewGroup +import android.widget.LinearLayout +import android.widget.RelativeLayout +import xyz.mtfos.tools.apiObject +import xyz.mtfos.tools.objectTool.bind + +/** + * Created by jay on 2017/7/6. + */ +open class SampleActivity : Activity() { + protected val api: apiObject = apiObject(this@SampleActivity) + protected val layMain: RelativeLayout by bind(R.id.layMain) + protected val layLoading: LinearLayout by bind(R.id.layLoading) + + fun setViewSource(v: View?) { + setContentView(v) + setDynView() + } + + fun setViewSource(v: Int) { + setContentView(v) + setDynView() + } + + fun setDynView() { + val loadingItem: LinearLayout = layoutInflater.inflate(R.layout.lay_loading, null) as LinearLayout + + loadingItem.layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT) + + layLoading?.addView(loadingItem) + } + + fun toggleLoading(flag: Boolean) { + layLoading?.visibility = if (flag == true) { + View.VISIBLE + } else { + View.GONE + } + } +} \ No newline at end of file diff --git a/app/src/main/java/xyz/mtfos/buywhat/StoreList.kt b/app/src/main/java/xyz/mtfos/buywhat/StoreList.kt index d0360c1..77ac50f 100644 --- a/app/src/main/java/xyz/mtfos/buywhat/StoreList.kt +++ b/app/src/main/java/xyz/mtfos/buywhat/StoreList.kt @@ -1,7 +1,6 @@ package xyz.mtfos.buywhat import android.annotation.SuppressLint -import android.app.Activity import android.content.Context import android.content.Intent import android.os.Bundle @@ -18,28 +17,28 @@ import xyz.mtfos.tools.objectTool.bind /** * Created by jay on 2017/7/5. */ -class StoreList : Activity() { +class StoreList : SampleActivity() { private val lv: ListView by bind(R.id.storelv) - private val tvTitle: TextView by bind(R.id.tvTitle) private val ivRefresh: ImageView by bind(R.id.ivRefresh) - private val api: apiObject = apiObject(this@StoreList) private var storeList: ArrayList = ArrayList() private var adapter: lvAdapter? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setContentView(R.layout.activity_store_list) + setViewSource(R.layout.activity_store_list) adapter = lvAdapter(this@StoreList, 0) lv.adapter = adapter - lv.setOnItemClickListener({parent, view, position, id -> + lv.setOnItemClickListener({ parent, view, position, id -> val data: JSONObject = storeList.get(position) as JSONObject val sid: Int = data!!["id"] as Int + val name: String = data!!["name"] as String - var intent = Intent(this@StoreList, null) + val intent = Intent(this@StoreList, ItemRandom::class.java) intent.putExtra("id", sid) + intent.putExtra("name", name) startActivity(intent) }) @@ -51,13 +50,15 @@ class StoreList : Activity() { } fun getList() { + toggleLoading(true) api.getStore(object : apiObject.apicb { override fun Callback(json: JSONObject?) { + uiHandler.post({ toggleLoading(false) }) if (json!!["status"] == 1) { var jarr: JSONArray = json!!["record"] as JSONArray - if(jarr.length() > 0) { - storeList.clear() - for(i in 0..(jarr.length() - 1)) { + storeList.clear() + if (jarr.length() > 0) { + for (i in 0..(jarr.length() - 1)) { val tmp = jarr.getJSONObject(i) storeList.add(tmp) } @@ -82,13 +83,13 @@ class StoreList : Activity() { } } - class lvAdapter(context: Context, resource: Int): ArrayAdapter(context, resource) { + class lvAdapter(context: Context, resource: Int) : ArrayAdapter(context, resource) { override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View { val data = getItem(position) as JSONObject - var v: View = if(convertView == null) { + var v: View = if (convertView == null) { View.inflate(context, R.layout.listview_store_item, null) - }else { + } else { convertView } val tv: TextView = v.findViewById(R.id.tvItem) diff --git a/app/src/main/java/xyz/mtfos/tools/apiObject.kt b/app/src/main/java/xyz/mtfos/tools/apiObject.kt index 2891cec..10087de 100644 --- a/app/src/main/java/xyz/mtfos/tools/apiObject.kt +++ b/app/src/main/java/xyz/mtfos/tools/apiObject.kt @@ -37,7 +37,7 @@ open class apiObject constructor(val ctx: Context) { open fun getItems(storeId: Int, cb: apicb) { val url:String = "${projectSet.apiUrl}/item/${storeId}" - var req:Request = Request.Builder() + val req:Request = Request.Builder() .url(url) .build() send(req, object : apicb { diff --git a/app/src/main/res/drawable-hdpi/ic_keyboard_arrow_left_black_24dp.png b/app/src/main/res/drawable-hdpi/ic_keyboard_arrow_left_black_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..05b35790782ea7a19dcf00a4654ca22885441cb6 GIT binary patch literal 150 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k0wldT1B8K8tfz}(NCji^0&NM_#Rr%smobC=PSjnT~D5BuRfugiSwhxt|nnmXTF v5x97pkwNg`6}dcbctRLt9Fp6(fW|Q}$gOnxo5~;#vX8;j)z4*}Q$iB}!^kXV literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-mdpi/ic_keyboard_arrow_left_black_24dp.png b/app/src/main/res/drawable-mdpi/ic_keyboard_arrow_left_black_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..22b624b31f2a72ecb5a5c1493ebf0bc7563b6807 GIT binary patch literal 125 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM0wlfaz7_*17f%<*kP60R2iC<7j2xap{}?z@ zJp=#Ee`vtW&pTCK(f4N{TU=6XJ;RDW?9C<}o?X1hB`VrGr&aS9Em7sG{3P^HgMq;@ XQ}*l?dFh`(^B6o`{an^LB{Ts5c{L-V literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_keyboard_arrow_left_black_24dp.png b/app/src/main/res/drawable-xhdpi/ic_keyboard_arrow_left_black_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..49ef87d235163782d9b8ef17a9a7a00f16eda8e8 GIT binary patch literal 160 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA0wn)(8}b0DbWaz@kP61PlWqAN5=2mS&BA^>3w+*eS>SC`6}w28_n1U6v&gFQB*itdd_XH1JYD@< J);T3K0RZ8gIqv`f literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxhdpi/ic_keyboard_arrow_left_black_24dp.png b/app/src/main/res/drawable-xxhdpi/ic_keyboard_arrow_left_black_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..da52e03976085c9df3fac141e671e8ba5301c418 GIT binary patch literal 215 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY0wn)GsXhaw=6Sj}hEy=Vy|$P4kO70sL+Jy? z4en3$6DT;s*B9m$MXHxfeZ07I$F&J+ z9&_&*dnC(cHe7jnU+R*xYUh_LZj3Xh9LZeb8qFGdRuO2A(y!@u^_kp%e!XB40J@aH M)78&qol`;+0AiI@@Bjb+ literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxxhdpi/ic_keyboard_arrow_left_black_24dp.png b/app/src/main/res/drawable-xxxhdpi/ic_keyboard_arrow_left_black_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..55f211b166a62f3f3de316d0fcd052f916a29d5c GIT binary patch literal 191 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD0wg^q?%xcg+B{txLn;{Gp5HBaC_u#7@u@@q z1@`&jQUVvmEOuK?G~K+Kt;C5LsIXz`)!P5Nb3^aXZ#ngQazJ&xP}KYLdUwCyx7_u9 z-|yb<{O|rB|2zHnyWRII{=eM!`&~I(P0^`1&j|{SO)Q*3Djpz4OYx;S1!pyUb}YT{ kYM(vlcai8ykW(0bFeY-|4V!c1%wiDF)78&qol`;+0Q+%IGynhq literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable/logo.png b/app/src/main/res/drawable/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..bec307d71d181c339e24469f3350031f973bfe77 GIT binary patch literal 12295 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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +