@ -0,0 +1,45 @@ | |||||
package gq.yigit.mycity; | |||||
import android.graphics.Bitmap; | |||||
import android.graphics.BitmapFactory; | |||||
import android.os.AsyncTask; | |||||
import android.util.Log; | |||||
import java.io.InputStream; | |||||
import java.util.ArrayList; | |||||
import java.util.List; | |||||
public class ImageDownload extends AsyncTask<String, Void, Bitmap> { | |||||
private List<imageListener> listeners = new ArrayList<>(); | |||||
@Override | |||||
protected Bitmap doInBackground(String... URL) { | |||||
String imageURL = URL[0]; | |||||
Log.d("[BOOKMARK]",imageURL); | |||||
Bitmap bitmap = null; | |||||
try { | |||||
// Download Image from URL | |||||
InputStream input = new java.net.URL(imageURL).openStream(); | |||||
// Decode Bitmap | |||||
bitmap = BitmapFactory.decodeStream(input); | |||||
} catch (Exception e) { | |||||
e.printStackTrace(); | |||||
} | |||||
return bitmap; | |||||
} | |||||
@Override | |||||
protected void onPostExecute(Bitmap result) { | |||||
for (imageListener hl : listeners) | |||||
hl.imageDownloaded(result); | |||||
} | |||||
public void addListener(imageListener toAdd) { | |||||
listeners.add(toAdd); | |||||
} | |||||
} |
@ -1,4 +0,0 @@ | |||||
package gq.yigit.mycity; | |||||
public class VotesActivity { | |||||
} |
@ -0,0 +1,7 @@ | |||||
package gq.yigit.mycity; | |||||
import android.graphics.Bitmap; | |||||
public interface imageListener { | |||||
public void imageDownloaded(Bitmap img); | |||||
} |
@ -0,0 +1,77 @@ | |||||
package gq.yigit.mycity.vote; | |||||
import android.support.v7.widget.RecyclerView; | |||||
import android.util.Log; | |||||
import android.view.LayoutInflater; | |||||
import android.view.View; | |||||
import android.view.ViewGroup; | |||||
import android.widget.ImageView; | |||||
import android.widget.TextView; | |||||
import gq.yigit.mycity.R; | |||||
import gq.yigit.mycity.vote.VotesFragment.OnListFragmentInteractionListener; | |||||
import gq.yigit.mycity.vote.VotesContent.VoteItem; | |||||
import java.util.List; | |||||
public class MyVotesRecyclerViewAdapter extends RecyclerView.Adapter<MyVotesRecyclerViewAdapter.ViewHolder> { | |||||
private final List<VoteItem> mValues; | |||||
private final OnListFragmentInteractionListener mListener; | |||||
public MyVotesRecyclerViewAdapter(List<VoteItem> items, OnListFragmentInteractionListener listener) { | |||||
mValues = items; | |||||
mListener = listener; | |||||
} | |||||
@Override | |||||
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { | |||||
View view = LayoutInflater.from(parent.getContext()) | |||||
.inflate(R.layout.fragment_votes, parent, false); | |||||
return new ViewHolder(view); | |||||
} | |||||
@Override | |||||
public void onBindViewHolder(final ViewHolder holder, int position) { | |||||
holder.mItem = mValues.get(position); | |||||
holder.mIdView.setText(mValues.get(position).name); | |||||
holder.mContentView.setText(mValues.get(position).details); | |||||
holder.mImageView.setImageBitmap(mValues.get(position).img); | |||||
holder.mView.setOnClickListener(new View.OnClickListener() { | |||||
@Override | |||||
public void onClick(View v) { | |||||
if (null != mListener) { | |||||
mListener.onListFragmentInteraction(holder.mItem); | |||||
} | |||||
} | |||||
}); | |||||
} | |||||
@Override | |||||
public int getItemCount() { | |||||
return mValues.size(); | |||||
} | |||||
public class ViewHolder extends RecyclerView.ViewHolder { | |||||
public final View mView; | |||||
public final TextView mIdView; | |||||
public final TextView mContentView; | |||||
public final ImageView mImageView; | |||||
public VoteItem mItem; | |||||
public ViewHolder(View view) { | |||||
super(view); | |||||
mView = view; | |||||
mIdView = (TextView) view.findViewById(R.id.item_number); | |||||
mContentView = (TextView) view.findViewById(R.id.content); | |||||
mImageView = (ImageView) view.findViewById(R.id.vote_img); | |||||
} | |||||
@Override | |||||
public String toString() { | |||||
return super.toString() + " '" + mContentView.getText() + "'"; | |||||
} | |||||
} | |||||
} |
@ -0,0 +1,40 @@ | |||||
package gq.yigit.mycity.vote; | |||||
import android.graphics.Bitmap; | |||||
import java.util.ArrayList; | |||||
import java.util.HashMap; | |||||
import java.util.List; | |||||
import java.util.Map; | |||||
public class VotesContent { | |||||
public static final List<VoteItem> ITEMS = new ArrayList<VoteItem>(); | |||||
public static final Map<String, VoteItem> ITEM_MAP = new HashMap<String, VoteItem>(); | |||||
public static void addItem(VoteItem item) { | |||||
ITEMS.add(item); | |||||
ITEM_MAP.put(item.id, item); | |||||
} | |||||
public static class VoteItem { | |||||
public final String id; | |||||
public final String name; | |||||
public final String details; | |||||
public final Bitmap img; | |||||
public VoteItem(String id, String name, String details, Bitmap img) { | |||||
this.id = id; | |||||
this.name = name; | |||||
this.details = details; | |||||
this.img = img; | |||||
} | |||||
@Override | |||||
public String toString() { | |||||
return name; | |||||
} | |||||
} | |||||
} |
@ -0,0 +1,137 @@ | |||||
package gq.yigit.mycity.vote; | |||||
import android.content.Context; | |||||
import android.graphics.Bitmap; | |||||
import android.os.Bundle; | |||||
import android.support.v4.app.Fragment; | |||||
import android.support.v7.widget.GridLayoutManager; | |||||
import android.support.v7.widget.LinearLayoutManager; | |||||
import android.support.v7.widget.RecyclerView; | |||||
import android.util.Log; | |||||
import android.view.LayoutInflater; | |||||
import android.view.View; | |||||
import android.view.ViewGroup; | |||||
import gq.yigit.mycity.*; | |||||
import gq.yigit.mycity.vote.VotesContent.VoteItem; | |||||
import org.json.JSONArray; | |||||
import org.json.JSONObject; | |||||
import java.util.HashMap; | |||||
public class VotesFragment extends Fragment implements responseListener, imageListener { | |||||
private static final String ARG_COLUMN_COUNT = "column-count"; | |||||
private int mColumnCount = 1; | |||||
private OnListFragmentInteractionListener mListener; | |||||
public RecyclerView recyclerView; | |||||
public String url; | |||||
public int img_count = 0; | |||||
public JSONArray votes; | |||||
public ImageDownload img_downloader; | |||||
public int j = 0; | |||||
public VotesFragment() { | |||||
} | |||||
public static VotesFragment newInstance(int columnCount) { | |||||
VotesFragment fragment = new VotesFragment(); | |||||
Bundle args = new Bundle(); | |||||
args.putInt(ARG_COLUMN_COUNT, columnCount); | |||||
fragment.setArguments(args); | |||||
return fragment; | |||||
} | |||||
@Override | |||||
public void onCreate(Bundle savedInstanceState) { | |||||
super.onCreate(savedInstanceState); | |||||
if (getArguments() != null) { | |||||
mColumnCount = getArguments().getInt(ARG_COLUMN_COUNT); | |||||
} | |||||
} | |||||
@Override | |||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, | |||||
Bundle savedInstanceState) { | |||||
View view = inflater.inflate(R.layout.fragment_votes_list, container, false); | |||||
// Set the adapter | |||||
if (view instanceof RecyclerView) { | |||||
Context context = view.getContext(); | |||||
recyclerView = (RecyclerView) view; | |||||
if (mColumnCount <= 1) { | |||||
recyclerView.setLayoutManager(new LinearLayoutManager(context)); | |||||
} else { | |||||
recyclerView.setLayoutManager(new GridLayoutManager(context, mColumnCount)); | |||||
} | |||||
FileActions file_manager = new FileActions(); | |||||
url = (file_manager.readFromFile(context,"server.config")).trim(); | |||||
WebRequest web_manager = new WebRequest(url + "/votings",true,new HashMap<String,String>()); | |||||
web_manager.addListener(this); | |||||
web_manager.execute(); | |||||
} | |||||
return view; | |||||
} | |||||
@Override | |||||
public void onAttach(Context context) { | |||||
super.onAttach(context); | |||||
if (context instanceof OnListFragmentInteractionListener) { | |||||
mListener = (OnListFragmentInteractionListener) context; | |||||
} else { | |||||
throw new RuntimeException(context.toString() | |||||
+ " must implement OnListFragmentInteractionListener"); | |||||
} | |||||
} | |||||
@Override | |||||
public void onDetach() { | |||||
super.onDetach(); | |||||
mListener = null; | |||||
} | |||||
public interface OnListFragmentInteractionListener { | |||||
void onListFragmentInteraction(VoteItem item); | |||||
} | |||||
public void receivedResponse(boolean success, String response){ | |||||
if(success) { | |||||
try { | |||||
votes = new JSONArray(response); | |||||
img_downloader = new ImageDownload(); | |||||
img_downloader.addListener(this); | |||||
img_downloader.execute(url+ ((JSONObject)votes.get(j)).getString("img")); | |||||
}catch (Exception e){ | |||||
Log.e("[ERROR]:",e.getMessage()); | |||||
} | |||||
Log.i("[INFO]",VotesContent.ITEMS.toString()); | |||||
}else{ | |||||
Log.e("[ERROR]:",response); | |||||
} | |||||
} | |||||
public void imageDownloaded(Bitmap img){ | |||||
try { | |||||
JSONObject vote = (JSONObject) votes.get(j); | |||||
vote.put("img",img); | |||||
j++; | |||||
if(j>votes.length()-1) { | |||||
for (int i = 0; i < votes.length(); i++) { | |||||
JSONObject poll = (JSONObject) votes.get(i); | |||||
VotesContent.addItem(new VoteItem(poll.get("id").toString(), poll.get("name").toString(), poll.get("desc").toString(), (Bitmap) poll.get("img"))); | |||||
} | |||||
recyclerView.setAdapter(new MyVotesRecyclerViewAdapter(VotesContent.ITEMS, mListener)); | |||||
}else{ | |||||
img_downloader = new ImageDownload(); | |||||
img_downloader.addListener(this); | |||||
img_downloader.execute(url+ ((JSONObject)votes.get(j)).getString("img")); | |||||
} | |||||
} catch (Exception e) { | |||||
Log.e("[ERROR]", e.toString()); | |||||
} | |||||
} | |||||
} |
@ -0,0 +1,12 @@ | |||||
<?xml version="1.0" encoding="utf-8"?> | |||||
<shape xmlns:android="http://schemas.android.com/apk/res/android" | |||||
android:shape="rectangle"> | |||||
<corners | |||||
android:radius="2dp" | |||||
android:topRightRadius="0dp" | |||||
android:bottomRightRadius="0dp" | |||||
android:bottomLeftRadius="0dp"/> | |||||
<stroke | |||||
android:width="1dp" | |||||
android:color="@android:color/black" /> | |||||
</shape> |
@ -0,0 +1,37 @@ | |||||
<?xml version="1.0" encoding="utf-8"?> | |||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" | |||||
xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" | |||||
android:layout_height="wrap_content" | |||||
android:orientation="horizontal" | |||||
android:background="@drawable/vote_style" | |||||
android:layout_marginBottom="10dp"> | |||||
<ImageView | |||||
android:layout_width="150dp" | |||||
android:layout_height="50dp" app:srcCompat="@mipmap/ic_launcher" android:id="@+id/vote_img" | |||||
android:layout_weight="1"/> | |||||
<LinearLayout | |||||
android:orientation="vertical" | |||||
android:layout_width="match_parent" | |||||
android:layout_height="wrap_content" android:layout_weight="1"> | |||||
<TextView | |||||
android:id="@+id/item_number" | |||||
android:layout_width="match_parent" | |||||
android:layout_height="wrap_content" | |||||
android:layout_margin="4dp" | |||||
android:textAppearance="?attr/textAppearanceListItem" android:textSize="14sp"/> | |||||
<LinearLayout | |||||
android:orientation="vertical" | |||||
android:layout_width="match_parent" | |||||
android:layout_height="wrap_content" android:layout_weight="1" | |||||
android:layout_marginLeft="16dp"> | |||||
<TextView | |||||
android:id="@+id/content" | |||||
android:layout_width="match_parent" | |||||
android:layout_height="wrap_content" | |||||
android:layout_margin="4dp" | |||||
android:textAppearance="?attr/textAppearanceListItem" android:textColor="#b5b5b5" | |||||
android:textSize="12sp"/> | |||||
</LinearLayout> | |||||
</LinearLayout> | |||||
</LinearLayout> |
@ -0,0 +1,18 @@ | |||||
<?xml version="1.0" encoding="utf-8"?> | |||||
<android.support.v7.widget.RecyclerView | |||||
xmlns:android="http://schemas.android.com/apk/res/android" | |||||
xmlns:app="http://schemas.android.com/apk/res-auto" | |||||
xmlns:tools="http://schemas.android.com/tools" | |||||
android:id="@+id/list" | |||||
android:name="gq.yigit.mycity.VotesFragment" | |||||
android:layout_width="match_parent" | |||||
android:layout_height="wrap_content" | |||||
android:layout_marginLeft="16dp" | |||||
android:layout_marginTop="60dp" | |||||
android:layout_marginRight="16dp" | |||||
app:layoutManager="LinearLayoutManager" | |||||
tools:context=".vote.VotesFragment" | |||||
tools:listitem="@layout/fragment_votes" | |||||
android:divider="@android:color/transparent" | |||||
android:dividerHeight="100.0sp" | |||||
android:clipChildren="false" android:clipToPadding="false" android:scrollbars="vertical"/> |
@ -1,14 +0,0 @@ | |||||
<?xml version="1.0" encoding="utf-8"?> | |||||
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" | |||||
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" | |||||
android:layout_height="match_parent"> | |||||
<TextView | |||||
android:layout_width="wrap_content" | |||||
android:layout_height="wrap_content" | |||||
android:text="Bonjour!" | |||||
app:layout_constraintBottom_toBottomOf="parent" | |||||
app:layout_constraintLeft_toLeftOf="parent" | |||||
app:layout_constraintRight_toRightOf="parent" | |||||
app:layout_constraintTop_toTopOf="parent"/> | |||||
</android.support.constraint.ConstraintLayout> |
@ -1,84 +1,97 @@ | |||||
import os | import os | ||||
import ssl | |||||
import json | import json | ||||
from flask import Flask, send_from_directory | |||||
from flask_restful import Resource, Api, abort, reqparse | |||||
from flask import Flask, send_from_directory, request | |||||
from flask_restful import Resource, Api, abort | |||||
app = Flask(__name__) | app = Flask(__name__) | ||||
api = Api(app) | api = Api(app) | ||||
parser = reqparse.RequestParser() | |||||
parser.add_argument('name', required=True) | |||||
parser.add_argument('desc') | |||||
parser.add_argument('img') | |||||
parser.add_argument('votes', required=True) | |||||
with open(os.path.join(app.root_path, 'votings.json'), 'r') as f: | with open(os.path.join(app.root_path, 'votings.json'), 'r') as f: | ||||
votings = json.load(f) | |||||
votings = json.load(f) | |||||
class Votings(Resource): | class Votings(Resource): | ||||
def get(self): | |||||
voting = [ | |||||
{ | |||||
'id' : v['id'], | |||||
'name': v['name'], | |||||
'desc': v['desc'], | |||||
'img' : v['img'] | |||||
} | |||||
for v in votings | |||||
] | |||||
return voting | |||||
def post(self): | |||||
args = parser.parse_args() | |||||
voting_id = len(votings) + 1 | |||||
voting = { | |||||
'id': voting_id, | |||||
'name': args['name'], | |||||
'desc': args['desc'], | |||||
'img' : args['img'], | |||||
'votes': [ | |||||
{ | |||||
'id': k, | |||||
'name': vote['name'], | |||||
'desc': vote['desc'], | |||||
'votes': 0 | |||||
} | |||||
for k, vote in enumerate(json.loads(args['votes'])) | |||||
] | |||||
} | |||||
votings.append(voting) | |||||
with open(os.path.join(app.root_path, 'votings.json'), 'w') as f: | |||||
json.dump(votings, f, indent=4) | |||||
return voting | |||||
def get(self): | |||||
voting = [ | |||||
{ | |||||
'id' : v['id'], | |||||
'name': v['name'], | |||||
'desc': v['desc'], | |||||
'img' : v['img'] | |||||
} | |||||
for v in votings | |||||
] | |||||
return voting | |||||
def post(self): | |||||
""" | |||||
Example POST Data: | |||||
name=<voting_name>& | |||||
desc=<voting_desc>& # OPTIONAL | |||||
img=<voting_img>& # OPTIONAL | |||||
votes=[ | |||||
{ | |||||
"name": "<vote_name>", | |||||
"desc": "<vote_desc>" # OPTIONAL | |||||
}, | |||||
(...) | |||||
] | |||||
""" | |||||
args = request.form | |||||
voting_id = len(votings) + 1 | |||||
voting = { | |||||
'id': voting_id, | |||||
'name': args['name'], | |||||
'desc': args.get('desc'), | |||||
'img' : args.get('img'), | |||||
'votes': [ | |||||
{ | |||||
'id' : k, | |||||
'name': vote['name'], | |||||
'desc': vote.get('desc'), | |||||
'votes': 0 | |||||
} | |||||
for k, vote in enumerate(json.loads(args['votes'])) | |||||
] | |||||
} | |||||
votings.append(voting) | |||||
with open(os.path.join(app.root_path, 'votings.json'), 'w') as f: | |||||
json.dump(votings, f, indent=4) | |||||
return voting | |||||
class Voting(Resource): | class Voting(Resource): | ||||
def get(self, voting_id): | |||||
try: | |||||
return votings[voting_id - 1] | |||||
except: | |||||
abort(404, error="Voting {} doesn't exist".format(voting_id)) | |||||
def get(self, voting_id): | |||||
try: | |||||
return votings[voting_id - 1] | |||||
except: | |||||
abort(404, error="Voting {} doesn't exist".format(voting_id)) | |||||
class Vote(Resource): | class Vote(Resource): | ||||
def get(self, voting_id, vote_id): | |||||
votings[voting_id - 1]['votes'][vote_id - 1]['votes'] += 1 | |||||
with open(os.path.join(app.root_path, 'votings.json'), 'w') as f: | |||||
json.dump(votings, f, indent=4) | |||||
return votings[voting_id - 1] | |||||
def get(self): | |||||
""" | |||||
Example URL Query: | |||||
/vote?voting_id=<voting_id>&vote_id=<vote_id> | |||||
""" | |||||
voting_id = int(request.args['voting_id']) | |||||
vote_id = int(request.args['vote_id']) | |||||
votings[voting_id - 1]['votes'][vote_id - 1]['votes'] += 1 | |||||
with open(os.path.join(app.root_path, 'votings.json'), 'w') as f: | |||||
json.dump(votings, f, indent=4) | |||||
return votings[voting_id - 1] | |||||
api.add_resource(Votings, '/votings', '/votings/') | api.add_resource(Votings, '/votings', '/votings/') | ||||
api.add_resource(Voting, '/votings/<int:voting_id>') | api.add_resource(Voting, '/votings/<int:voting_id>') | ||||
api.add_resource(Vote, '/vote/<int:voting_id>/<int:vote_id>') | |||||
api.add_resource(Vote, '/vote', '/vote/') | |||||
@app.route('/img/<path:path>') | @app.route('/img/<path:path>') | ||||
def send_img(path): | def send_img(path): | ||||
return send_from_directory('images', path) | |||||
return send_from_directory('images', path) | |||||
if __name__ == '__main__': | if __name__ == '__main__': | ||||
app.run(host='0.0.0.0', port=5000, debug=True) | |||||
app.run(host='0.0.0.0', port=5000) |