From 52d15a80ca026d757b6e3c3637ae3d4be13f97b7 Mon Sep 17 00:00:00 2001 From: Niels Zwemmer Date: Wed, 28 Jun 2017 17:44:27 +0200 Subject: [PATCH 01/22] Working refresh, working user-specific posts in profile. --- .../tagram/CameraFragment.java | 5 ++- .../myhyvesbookplus/tagram/MainActivity.java | 1 - .../tagram/ProfileFragment.java | 18 ++++----- .../tagram/TimeLineAdapter.java | 4 +- .../tagram/TimelineFragment.java | 39 ++++++++++++++++++- .../tagram/controller/DownloadClass.java | 8 +++- .../res/layout/fragment_profile_timeline.xml | 3 +- .../src/main/res/layout/fragment_timeline.xml | 16 ++++++-- .../main/res/layout/list_item_timeline.xml | 2 - .../app/src/main/res/values-nl/strings.xml | 2 +- 10 files changed, 71 insertions(+), 27 deletions(-) diff --git a/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/CameraFragment.java b/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/CameraFragment.java index ca0bb4a..8c5af6f 100644 --- a/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/CameraFragment.java +++ b/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/CameraFragment.java @@ -161,7 +161,10 @@ public class CameraFragment extends Fragment implements PostUploader.PostUploadL mComment.setText(""); PostUploader upload = new PostUploader(getActivity()); - upload.uploadPicture(new BitmapPost(((PicturePreview)view.findViewById(R.id.pic_preview)).getPicture(), comment)); + if (R.id.pic_preview == 0) { + upload.uploadPicture(new BitmapPost(((PicturePreview)view.findViewById(R.id.pic_preview)).getPicture(), comment)); + + } mPhoto.recycle(); diff --git a/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/MainActivity.java b/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/MainActivity.java index 8772d76..a6a67e2 100644 --- a/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/MainActivity.java +++ b/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/MainActivity.java @@ -122,7 +122,6 @@ public class MainActivity extends AppCompatActivity implements public void PostDownloaded() { FragmentManager fragmentManager = getFragmentManager(); Fragment frag = fragmentManager.findFragmentById(R.id.content); - Log.d(TAG, "PostDownloaded: " + R.id.content); if (frag instanceof ProfileFragment) { ((ProfileFragment) frag).startList(); diff --git a/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/ProfileFragment.java b/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/ProfileFragment.java index 4f33ef2..0316efa 100644 --- a/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/ProfileFragment.java +++ b/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/ProfileFragment.java @@ -9,7 +9,6 @@ import android.os.Environment; import android.provider.MediaStore; import android.support.annotation.NonNull; import android.support.v4.content.FileProvider; -import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -49,7 +48,6 @@ public class ProfileFragment extends Fragment implements View.OnClickListener { protected File photoFile = null; private ListView listView; private DownloadClass downloadClass; - ProgressDialog progressDialog; /// Required empty public constructor /// @@ -87,14 +85,13 @@ public class ProfileFragment extends Fragment implements View.OnClickListener { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View viewTimeline = inflater.inflate(R.layout.fragment_profile_timeline, container, false); - - - - listView = (ListView) viewTimeline.findViewById(R.id.listview_profile); + listView = (ListView) viewTimeline.findViewById(R.id.list); View viewHeader = inflater.inflate(R.layout.fragment_profile_header, listView, false); findViews(viewHeader); listView.addHeaderView(viewHeader); + profilePicture.invalidate(); + if (user != null) { if(user.getPhotoUrl() != null) { httpsReference = FirebaseStorage.getInstance().getReferenceFromUrl(user.getPhotoUrl().toString()); @@ -109,11 +106,10 @@ public class ProfileFragment extends Fragment implements View.OnClickListener { Glide.with(this).using(new FirebaseImageLoader()).load(httpsReference).into(profilePicture); } - profilePicture.invalidate(); - downloadClass = new DownloadClass(getActivity()); + + downloadClass = new DownloadClass(getActivity(), "profile"); downloadClass.getPostsFromServer(); - return viewTimeline; } @@ -158,8 +154,8 @@ public class ProfileFragment extends Fragment implements View.OnClickListener { } public void startList() { - ProfileAdapter adapter = new ProfileAdapter(getActivity(), downloadClass.getmList()); - listView.setAdapter(adapter); + ProfileAdapter adapter = new ProfileAdapter(getActivity(), downloadClass.getOwnPosts()); + listView.setAdapter(adapter); } /** diff --git a/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/TimeLineAdapter.java b/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/TimeLineAdapter.java index ff4b341..3d6cbb4 100644 --- a/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/TimeLineAdapter.java +++ b/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/TimeLineAdapter.java @@ -58,7 +58,7 @@ public class TimeLineAdapter extends BaseAdapter implements AdapterView.OnItemCl public View getView(int position, View convertView, ViewGroup parent) { View rowView = mInflater.inflate(R.layout.list_item_timeline, parent, false); -// TextView userName = (TextView) rowView.findViewById(R.id.username_timeline); + TextView userName = (TextView) rowView.findViewById(R.id.username_timeline); TextView comment = (TextView) rowView.findViewById(R.id.comment_timeline); TextView nietSlechts = (TextView) rowView.findViewById(R.id.niet_slecht_count); ImageView photo = (ImageView) rowView.findViewById(R.id.timeline_image); @@ -73,7 +73,7 @@ public class TimeLineAdapter extends BaseAdapter implements AdapterView.OnItemCl UriPost post = (UriPost) getItem(position); -// userName.setText(); + userName.setText(post.getPoster()); nietSlechts.setText(Integer.toString(post.getNietSlechts())); comment.setText(post.getComment()); diff --git a/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/TimelineFragment.java b/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/TimelineFragment.java index b2ca6d4..db99e77 100644 --- a/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/TimelineFragment.java +++ b/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/TimelineFragment.java @@ -2,11 +2,16 @@ package nl.myhyvesbookplus.tagram; import android.app.Fragment; import android.os.Bundle; +import android.os.Handler; +import android.support.v4.widget.SwipeRefreshLayout; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.AbsListView; import android.widget.ListView; + + import nl.myhyvesbookplus.tagram.controller.DownloadClass; @@ -23,11 +28,41 @@ public class TimelineFragment extends Fragment { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_timeline, container, false); - listView = (ListView) view.findViewById(R.id.listview); + listView = (ListView) view.findViewById(R.id.list); + final SwipeRefreshLayout swipeView = (SwipeRefreshLayout) view.findViewById(R.id.swipe); - downloadClass = new DownloadClass(getActivity()); + swipeView.setEnabled(false); + downloadClass = new DownloadClass(getActivity(), "timeline"); downloadClass.getPostsFromServer(); + swipeView.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { + @Override + public void onRefresh() { + downloadClass = new DownloadClass(getActivity(), "timeline"); + downloadClass.getPostsFromServer(); + swipeView.setRefreshing(true); + ( new Handler()).postDelayed(new Runnable() { + @Override + public void run() { + swipeView.setRefreshing(false); + } + }, 3000); + } + }); + + listView.setOnScrollListener(new AbsListView.OnScrollListener() { + @Override + public void onScrollStateChanged(AbsListView absListView, int i) { + } + + @Override + public void onScroll(AbsListView absListView, int firstVisibleItem, int visibleItemCount, int totalItemCount) { + if (firstVisibleItem == 0) + swipeView.setEnabled(true); + else + swipeView.setEnabled(false); + } + }); return view; } diff --git a/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/controller/DownloadClass.java b/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/controller/DownloadClass.java index 64bf26c..cd5e0e0 100644 --- a/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/controller/DownloadClass.java +++ b/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/controller/DownloadClass.java @@ -24,8 +24,9 @@ public class DownloadClass { private DatabaseReference mDataRef; private ArrayList mList; private PostDownloadListener mListener; + private String fragmentName; - public DownloadClass(Context context) { + public DownloadClass(Context context, String fragmentName) { if (context instanceof DownloadClass.PostDownloadListener) { mListener = (PostDownloadListener) context; } else { @@ -34,6 +35,7 @@ public class DownloadClass { } mDataRef = FirebaseDatabase.getInstance().getReference(); mList = new ArrayList<>(); + this.fragmentName = fragmentName; } public void getPostsFromServer() { @@ -46,6 +48,7 @@ public class DownloadClass { mList.add(data.getValue(UriPost.class)); } Collections.reverse(mList); + mListener.PostDownloaded(); } @@ -62,13 +65,14 @@ public class DownloadClass { public ArrayList getOwnPosts() { String currentUid = FirebaseAuth.getInstance().getCurrentUser().getUid(); - ArrayList posts = new ArrayList(); + ArrayList posts = new ArrayList<>(); for (UriPost post : mList) { if (post.getPoster().equals(currentUid)) { posts.add(post); } } + return posts; } diff --git a/app/MyHyvesBookPlusStagram/app/src/main/res/layout/fragment_profile_timeline.xml b/app/MyHyvesBookPlusStagram/app/src/main/res/layout/fragment_profile_timeline.xml index fd06e94..523ff58 100644 --- a/app/MyHyvesBookPlusStagram/app/src/main/res/layout/fragment_profile_timeline.xml +++ b/app/MyHyvesBookPlusStagram/app/src/main/res/layout/fragment_profile_timeline.xml @@ -6,9 +6,8 @@ tools:context="nl.myhyvesbookplus.tagram.TimelineFragment"> - \ No newline at end of file diff --git a/app/MyHyvesBookPlusStagram/app/src/main/res/layout/fragment_timeline.xml b/app/MyHyvesBookPlusStagram/app/src/main/res/layout/fragment_timeline.xml index bfc4bea..9aa7a7d 100644 --- a/app/MyHyvesBookPlusStagram/app/src/main/res/layout/fragment_timeline.xml +++ b/app/MyHyvesBookPlusStagram/app/src/main/res/layout/fragment_timeline.xml @@ -5,11 +5,21 @@ android:orientation="vertical" tools:context="nl.myhyvesbookplus.tagram.TimelineFragment"> - + android:layout_height="match_parent" + > + + + + + \ No newline at end of file diff --git a/app/MyHyvesBookPlusStagram/app/src/main/res/layout/list_item_timeline.xml b/app/MyHyvesBookPlusStagram/app/src/main/res/layout/list_item_timeline.xml index d5e5f63..cce0278 100644 --- a/app/MyHyvesBookPlusStagram/app/src/main/res/layout/list_item_timeline.xml +++ b/app/MyHyvesBookPlusStagram/app/src/main/res/layout/list_item_timeline.xml @@ -9,13 +9,11 @@ android:layout_width="match_parent" android:layout_height="15dp" /> - Voer alstublieft email en wachtwoord in Er is een fout opgetreden. Controleer internetverbinding. Er is een e-mail verzonden. Volg a.u.b. de instructies. - Wachtwoorden komen niet overeen + Wachtwoorden komoen niet overeen Vul alstublieft alle velden in Opslaan Uploaden -- 2.49.1 From ab79fa7d7c32ff29bd851bcf7374e6959639de0b Mon Sep 17 00:00:00 2001 From: Niels Zwemmer Date: Wed, 28 Jun 2017 17:58:32 +0200 Subject: [PATCH 02/22] Changed some appearances of the personal posts. --- .../java/nl/myhyvesbookplus/tagram/CameraFragment.java | 5 +---- .../app/src/main/res/layout/list_item_timeline.xml | 2 +- .../src/main/res/layout/list_item_timeline_profile.xml | 8 ++++++-- .../app/src/main/res/values-nl/strings.xml | 1 + .../app/src/main/res/values/strings.xml | 2 ++ 5 files changed, 11 insertions(+), 7 deletions(-) diff --git a/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/CameraFragment.java b/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/CameraFragment.java index 8c5af6f..ca0bb4a 100644 --- a/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/CameraFragment.java +++ b/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/CameraFragment.java @@ -161,10 +161,7 @@ public class CameraFragment extends Fragment implements PostUploader.PostUploadL mComment.setText(""); PostUploader upload = new PostUploader(getActivity()); - if (R.id.pic_preview == 0) { - upload.uploadPicture(new BitmapPost(((PicturePreview)view.findViewById(R.id.pic_preview)).getPicture(), comment)); - - } + upload.uploadPicture(new BitmapPost(((PicturePreview)view.findViewById(R.id.pic_preview)).getPicture(), comment)); mPhoto.recycle(); diff --git a/app/MyHyvesBookPlusStagram/app/src/main/res/layout/list_item_timeline.xml b/app/MyHyvesBookPlusStagram/app/src/main/res/layout/list_item_timeline.xml index cce0278..e4d92b8 100644 --- a/app/MyHyvesBookPlusStagram/app/src/main/res/layout/list_item_timeline.xml +++ b/app/MyHyvesBookPlusStagram/app/src/main/res/layout/list_item_timeline.xml @@ -26,7 +26,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" - android:text="Hallo Ik ben een comment!" /> + android:text="@string/comment_placeholder" /> + android:text="@string/comment_placeholder" /> + android:text=" 10" /> diff --git a/app/MyHyvesBookPlusStagram/app/src/main/res/values-nl/strings.xml b/app/MyHyvesBookPlusStagram/app/src/main/res/values-nl/strings.xml index 4e7f662..f02108c 100644 --- a/app/MyHyvesBookPlusStagram/app/src/main/res/values-nl/strings.xml +++ b/app/MyHyvesBookPlusStagram/app/src/main/res/values-nl/strings.xml @@ -34,4 +34,5 @@ Niet Slecht. Bijschrift: Annuleer + Hallo Ik ben een comment! \ No newline at end of file diff --git a/app/MyHyvesBookPlusStagram/app/src/main/res/values/strings.xml b/app/MyHyvesBookPlusStagram/app/src/main/res/values/strings.xml index 8909894..afa90b1 100644 --- a/app/MyHyvesBookPlusStagram/app/src/main/res/values/strings.xml +++ b/app/MyHyvesBookPlusStagram/app/src/main/res/values/strings.xml @@ -32,4 +32,6 @@ Uploading profile picture… Comment: Cancel + Hello, I am a comment! + Er is een e-mail verzonden. Volg a.u.b. de instructies. -- 2.49.1 From 1fdd21440be2492c57eb4fb7a8c91d27b35f11ca Mon Sep 17 00:00:00 2001 From: Niels Zwemmer Date: Wed, 28 Jun 2017 19:46:38 +0200 Subject: [PATCH 03/22] Potentially fixed Felix' bug in the camera. Also made some changes for better readability of my own code. --- .../tagram/CameraFragment.java | 21 +++++----- .../tagram/ProfileFragment.java | 39 +++++++++++-------- .../tagram/TimelineFragment.java | 4 +- .../tagram/controller/DownloadClass.java | 4 +- 4 files changed, 35 insertions(+), 33 deletions(-) diff --git a/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/CameraFragment.java b/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/CameraFragment.java index 3bdc1b5..818fa47 100644 --- a/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/CameraFragment.java +++ b/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/CameraFragment.java @@ -149,6 +149,7 @@ public class CameraFragment extends Fragment implements PostUploader.PostUploadL view.findViewById(R.id.comment_box).bringToFront(); view.findViewById(R.id.filter_buttons).setVisibility(View.GONE); ((FloatingActionButton)view.findViewById(R.id.upload_button)).hide(); + hideKeyboard(); } }); @@ -179,6 +180,7 @@ public class CameraFragment extends Fragment implements PostUploader.PostUploadL view.findViewById(R.id.switch_camera_button).bringToFront(); mCameraLayout.removeView(view.findViewById(R.id.pic_preview)); + hideKeyboard(); } }); @@ -203,6 +205,7 @@ public class CameraFragment extends Fragment implements PostUploader.PostUploadL view.findViewById(R.id.switch_camera_button).bringToFront(); mCameraLayout.removeView(view.findViewById(R.id.pic_preview)); + hideKeyboard(); } }); @@ -242,21 +245,15 @@ public class CameraFragment extends Fragment implements PostUploader.PostUploadL } }); - (view.findViewById(R.id.comment_text)).setOnFocusChangeListener(new View.OnFocusChangeListener() { - @Override - public void onFocusChange(View v, boolean hasFocus) { - if (!hasFocus) { - hideKeyboard(v); - } - } - }); - return view; } - public void hideKeyboard(View view) { - InputMethodManager inputMethodManager =(InputMethodManager) getActivity().getSystemService(Activity.INPUT_METHOD_SERVICE); - inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), 0); + /** + * Hides keyboard after submit, upload or cancel button gets pressed. + */ + public void hideKeyboard() { + ((InputMethodManager) getActivity().getSystemService(Activity.INPUT_METHOD_SERVICE)) + .toggleSoftInput(InputMethodManager.SHOW_IMPLICIT, 0); } // TODO: Rename method, update argument and hook method into UI event diff --git a/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/ProfileFragment.java b/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/ProfileFragment.java index 0316efa..b6cfce8 100644 --- a/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/ProfileFragment.java +++ b/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/ProfileFragment.java @@ -45,9 +45,12 @@ public class ProfileFragment extends Fragment implements View.OnClickListener { protected TextView profileName; protected ImageView profilePicture; protected FirebaseUser user; - protected File photoFile = null; + protected File photoFile; private ListView listView; private DownloadClass downloadClass; + private View headerInflater; + private View timeLineInflater; + ProgressDialog progressDialog; /// Required empty public constructor /// @@ -58,19 +61,25 @@ public class ProfileFragment extends Fragment implements View.OnClickListener { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); user = FirebaseAuth.getInstance().getCurrentUser(); + photoFile = null; } /** - * Assigns all views and buttons. + * Assigns all views and buttons for the header. */ - protected void findViews(View view) { - profilePicButton = (ImageButton) view.findViewById(R.id.profile_pic_button); - profilePicture = (ImageView) view.findViewById(R.id.imageView_profile_picture); - profileName = (TextView) view.findViewById(R.id.profile_name); - changePwdButton = (Button) view.findViewById(R.id.change_psw_button); + protected void findHeaderViews() { + profilePicButton = (ImageButton) headerInflater.findViewById(R.id.profile_pic_button); + profilePicture = (ImageView) headerInflater.findViewById(R.id.imageView_profile_picture); + profileName = (TextView) headerInflater.findViewById(R.id.profile_name); + changePwdButton = (Button) headerInflater.findViewById(R.id.change_psw_button); bindOnClick(); } + protected void findTimelineViews() { + listView = (ListView) timeLineInflater.findViewById(R.id.list); + listView.addHeaderView(headerInflater); + } + /** * Bind the buttons to their listeners. */ @@ -84,11 +93,11 @@ public class ProfileFragment extends Fragment implements View.OnClickListener { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View viewTimeline = inflater.inflate(R.layout.fragment_profile_timeline, container, false); - listView = (ListView) viewTimeline.findViewById(R.id.list); - View viewHeader = inflater.inflate(R.layout.fragment_profile_header, listView, false); - findViews(viewHeader); - listView.addHeaderView(viewHeader); + + timeLineInflater = inflater.inflate(R.layout.fragment_profile_timeline, container, false); + headerInflater = inflater.inflate(R.layout.fragment_profile_header, listView, false); + findHeaderViews(); + findTimelineViews(); profilePicture.invalidate(); @@ -106,11 +115,9 @@ public class ProfileFragment extends Fragment implements View.OnClickListener { Glide.with(this).using(new FirebaseImageLoader()).load(httpsReference).into(profilePicture); } - - - downloadClass = new DownloadClass(getActivity(), "profile"); + downloadClass = new DownloadClass(getActivity()); downloadClass.getPostsFromServer(); - return viewTimeline; + return timeLineInflater; } /** diff --git a/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/TimelineFragment.java b/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/TimelineFragment.java index db99e77..7d41818 100644 --- a/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/TimelineFragment.java +++ b/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/TimelineFragment.java @@ -32,13 +32,13 @@ public class TimelineFragment extends Fragment { final SwipeRefreshLayout swipeView = (SwipeRefreshLayout) view.findViewById(R.id.swipe); swipeView.setEnabled(false); - downloadClass = new DownloadClass(getActivity(), "timeline"); + downloadClass = new DownloadClass(getActivity()); downloadClass.getPostsFromServer(); swipeView.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { @Override public void onRefresh() { - downloadClass = new DownloadClass(getActivity(), "timeline"); + downloadClass = new DownloadClass(getActivity()); downloadClass.getPostsFromServer(); swipeView.setRefreshing(true); ( new Handler()).postDelayed(new Runnable() { diff --git a/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/controller/DownloadClass.java b/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/controller/DownloadClass.java index cd5e0e0..819b772 100644 --- a/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/controller/DownloadClass.java +++ b/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/controller/DownloadClass.java @@ -24,9 +24,8 @@ public class DownloadClass { private DatabaseReference mDataRef; private ArrayList mList; private PostDownloadListener mListener; - private String fragmentName; - public DownloadClass(Context context, String fragmentName) { + public DownloadClass(Context context) { if (context instanceof DownloadClass.PostDownloadListener) { mListener = (PostDownloadListener) context; } else { @@ -35,7 +34,6 @@ public class DownloadClass { } mDataRef = FirebaseDatabase.getInstance().getReference(); mList = new ArrayList<>(); - this.fragmentName = fragmentName; } public void getPostsFromServer() { -- 2.49.1 From 26a7239caa4cc89209ce65916e01740a9933b802 Mon Sep 17 00:00:00 2001 From: Niels Zwemmer Date: Thu, 29 Jun 2017 00:35:55 +0200 Subject: [PATCH 04/22] Much cleaner code. Known bugs seem to be fixed. Added extra progressDialog for posts downloading. --- .../tagram/CameraFragment.java | 117 +++++------------- .../myhyvesbookplus/tagram/LoginActivity.java | 4 +- .../myhyvesbookplus/tagram/MainActivity.java | 14 +-- .../tagram/ProfileAdapter.java | 2 +- .../tagram/ProfileFragment.java | 55 +++++--- .../tagram/TimelineFragment.java | 51 +++++--- .../app/src/main/res/values-nl/strings.xml | 8 +- .../app/src/main/res/values/strings.xml | 8 +- 8 files changed, 120 insertions(+), 139 deletions(-) diff --git a/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/CameraFragment.java b/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/CameraFragment.java index 818fa47..ab95c27 100644 --- a/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/CameraFragment.java +++ b/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/CameraFragment.java @@ -24,27 +24,8 @@ import android.widget.RelativeLayout; import nl.myhyvesbookplus.tagram.controller.PostUploader; import nl.myhyvesbookplus.tagram.model.BitmapPost; -/** - * A simple {@link Fragment} subclass. - * Activities that contain this fragment must implement the - * {@link CameraFragment.OnFragmentInteractionListener} interface - * to handle interaction events. - * Use the {@link CameraFragment#newInstance} factory method to - * create an instance of this fragment. - */ public class CameraFragment extends Fragment implements PostUploader.PostUploadListener{ - // TODO: Rename parameter arguments, choose names that match private static final String TAG = "CameraFragment"; - // the fragment initialization parameters, e.g. ARG_ITEM_NUMBER - private static final String ARG_PARAM1 = "param1"; - private static final String ARG_PARAM2 = "param2"; - - // TODO: Rename and change types of parameters - private String mParam1; - private String mParam2; - - private OnFragmentInteractionListener mListener; - private Camera mCamera; private CameraPreview mPreview; private Bitmap mPhoto; @@ -54,33 +35,6 @@ public class CameraFragment extends Fragment implements PostUploader.PostUploadL // Required empty public constructor } - /** - * Use this factory method to create a new instance of - * this fragment using the provided parameters. - * - * @param param1 Parameter 1. - * @param param2 Parameter 2. - * @return A new instance of fragment CameraFragment. - */ - // TODO: Rename and change types and number of parameters - public static CameraFragment newInstance(String param1, String param2) { - CameraFragment fragment = new CameraFragment(); - Bundle args = new Bundle(); - args.putString(ARG_PARAM1, param1); - args.putString(ARG_PARAM2, param2); - fragment.setArguments(args); - return fragment; - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - if (getArguments() != null) { - mParam1 = getArguments().getString(ARG_PARAM1); - mParam2 = getArguments().getString(ARG_PARAM2); - } - } - @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { @@ -98,11 +52,12 @@ public class CameraFragment extends Fragment implements PostUploader.PostUploadL mCameraLayout.addView(mPreview); - // Draw buttons over preview + // Draw initial buttons over preview view.findViewById(R.id.picture_button).bringToFront(); view.findViewById(R.id.switch_camera_button).bringToFront(); filterButtons.bringToFront(); + /* Upon pressing the switch camera facing button: */ (view.findViewById(R.id.switch_camera_button)).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { @@ -119,6 +74,7 @@ public class CameraFragment extends Fragment implements PostUploader.PostUploadL } }); + /* Upon pressing the take photo button: */ (view.findViewById(R.id.picture_button)).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { @@ -141,6 +97,7 @@ public class CameraFragment extends Fragment implements PostUploader.PostUploadL } }); + /* Upon pressing the upload button: */ (view.findViewById(R.id.upload_button)).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { @@ -153,6 +110,7 @@ public class CameraFragment extends Fragment implements PostUploader.PostUploadL } }); + /* Upon pressing the enter button on the virtual keyboard: */ (view.findViewById(R.id.comment_submit)).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { @@ -184,6 +142,7 @@ public class CameraFragment extends Fragment implements PostUploader.PostUploadL } }); + /* Upon pressing the cancel button: */ (view.findViewById(R.id.comment_cancel)).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { @@ -209,6 +168,7 @@ public class CameraFragment extends Fragment implements PostUploader.PostUploadL } }); + /* Upon pressing the left arrow filter change button: */ (view.findViewById(R.id.filter_left)).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { @@ -227,6 +187,7 @@ public class CameraFragment extends Fragment implements PostUploader.PostUploadL } }); + /* Upon pressing the right arrow filter change button: */ (view.findViewById(R.id.filter_right)).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { @@ -256,30 +217,7 @@ public class CameraFragment extends Fragment implements PostUploader.PostUploadL .toggleSoftInput(InputMethodManager.SHOW_IMPLICIT, 0); } - // TODO: Rename method, update argument and hook method into UI event - public void onButtonPressed(Uri uri) { - if (mListener != null) { - mListener.onFragmentInteraction(uri); - } - } - - @Override - public void onAttach(Context context) { - super.onAttach(context); - if (context instanceof OnFragmentInteractionListener) { - mListener = (OnFragmentInteractionListener) context; - } else { - throw new RuntimeException(context.toString() - + " must implement OnFragmentInteractionListener"); - } - } - - @Override - public void onDetach() { - super.onDetach(); - mListener = null; - } - + //TODO Niet helemaal zeker wat dit doet. @Override public void onDestroyView() { super.onDestroyView(); @@ -291,6 +229,11 @@ public class CameraFragment extends Fragment implements PostUploader.PostUploadL getActivity().findViewById(R.id.content).setPadding(dp,dp,dp,dp); } + /** + * Start the camera. + * @param facing The direction in which the camera should be initialized (back by default). + * @return the result of the opened camera, if successful. + */ public static Camera getCameraInstance(int facing) { Camera c = null; try { @@ -301,13 +244,27 @@ public class CameraFragment extends Fragment implements PostUploader.PostUploadL return c; } + + /** + * Switch between front facing camera and the back camera. + */ public void switchFacing() { if (facing == Camera.CameraInfo.CAMERA_FACING_FRONT) facing = Camera.CameraInfo.CAMERA_FACING_BACK; else facing = Camera.CameraInfo.CAMERA_FACING_FRONT; +// TODO +// facing = +// facing == Camera.CameraInfo.CAMERA_FACING_FRONT ? +// Camera.CameraInfo.CAMERA_FACING_BACK : +// Camera.CameraInfo.CAMERA_FACING_FRONT; } + /** + * Change which buttons are visible during the different stages on the camera fragment. + * + * @param view The current view upon which the buttons need to be placed or removed. + */ public void switchButtons(View view) { FloatingActionButton upload = (FloatingActionButton) view.findViewById(R.id.upload_button); ImageButton picButton = (ImageButton) view.findViewById(R.id.picture_button); @@ -332,6 +289,8 @@ public class CameraFragment extends Fragment implements PostUploader.PostUploadL } } + + //TODO: Kan dit weg? super aanroepen enzo. @Override public void onPause() { super.onPause(); @@ -346,20 +305,4 @@ public class CameraFragment extends Fragment implements PostUploader.PostUploadL public void PostUploadComplete(Boolean success) { } - - /** - * This interface must be implemented by activities that contain this - * fragment to allow an interaction in this fragment to be communicated - * to the activity and potentially other fragments contained in that - * activity. - *

- * See the Android Training lesson Communicating with Other Fragments for more information. - */ - public interface OnFragmentInteractionListener { - // TODO: Update argument type and name - void onFragmentInteraction(Uri uri); - } - } diff --git a/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/LoginActivity.java b/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/LoginActivity.java index 46befe8..438db9f 100644 --- a/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/LoginActivity.java +++ b/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/LoginActivity.java @@ -181,7 +181,7 @@ public class LoginActivity extends AppCompatActivity implements View.OnClickList * @param passwordString the entered password */ protected void logIn(String emailString, String passwordString) { - progressDialog = ProgressDialog.show(LoginActivity.this, getString(R.string.please_wait), "Logging in", true, false); + progressDialog = ProgressDialog.show(LoginActivity.this, getString(R.string.please_wait), getString(R.string.logging_in), true, false); mAuth.signInWithEmailAndPassword(emailString, passwordString) .addOnCompleteListener(this, new OnCompleteListener() { @@ -211,7 +211,7 @@ public class LoginActivity extends AppCompatActivity implements View.OnClickList * @param password the entered password */ protected void registerUser(String email, String password) { - this.progressDialog = ProgressDialog.show(LoginActivity.this, getString(R.string.please_wait), "Registering", true, false); + this.progressDialog = ProgressDialog.show(LoginActivity.this, getString(R.string.please_wait), getString(R.string.registering), true, false); mAuth.createUserWithEmailAndPassword(email, password) .addOnCompleteListener(this, new OnCompleteListener() { @Override diff --git a/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/MainActivity.java b/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/MainActivity.java index a6a67e2..28b3a6d 100644 --- a/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/MainActivity.java +++ b/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/MainActivity.java @@ -20,9 +20,10 @@ import nl.myhyvesbookplus.tagram.controller.PostUploader; import nl.myhyvesbookplus.tagram.controller.ProfilePictureUploader; public class MainActivity extends AppCompatActivity implements - CameraFragment.OnFragmentInteractionListener, ProfilePictureUploader.ProfilePictureUpdatedListener, - DownloadClass.PostDownloadListener, PostUploader.PostUploadListener { + DownloadClass.PostDownloadListener, + PostUploader.PostUploadListener { + final static private String TAG = "MainScreen"; FirebaseAuth mAuth; @@ -89,11 +90,6 @@ public class MainActivity extends AppCompatActivity implements finish(); } - @Override - public void onFragmentInteraction(Uri uri) { - - } - public void logOutOnClick(View view) { FirebaseAuth.getInstance().signOut(); goToLogin(); @@ -107,7 +103,6 @@ public class MainActivity extends AppCompatActivity implements @Override public void ProfilePictureUpdated(Boolean success) { - Log.d(TAG, "ProfilePictureUpdated: Ja ik luister naar je!"); FragmentManager man = getFragmentManager(); ProfileFragment frag = (ProfileFragment) man.findFragmentById(R.id.content); FragmentTransaction transaction = man.beginTransaction(); @@ -123,9 +118,12 @@ public class MainActivity extends AppCompatActivity implements FragmentManager fragmentManager = getFragmentManager(); Fragment frag = fragmentManager.findFragmentById(R.id.content); + + if (frag instanceof ProfileFragment) { ((ProfileFragment) frag).startList(); } else if (frag instanceof TimelineFragment) { + ((TimelineFragment) frag).progressDialog.dismiss(); ((TimelineFragment) frag).startList(); } } diff --git a/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/ProfileAdapter.java b/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/ProfileAdapter.java index 357876a..3bff416 100644 --- a/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/ProfileAdapter.java +++ b/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/ProfileAdapter.java @@ -70,7 +70,7 @@ public class ProfileAdapter extends BaseAdapter { return newRowView; } - protected View findViews(View rowView) { + private View findViews(View rowView) { comment = (TextView) rowView.findViewById(R.id.comment_timeline_profile); nietSlechts = (TextView) rowView.findViewById(R.id.niet_slecht_count_profile); photo = (ImageView) rowView.findViewById(R.id.timeline_image_profile); diff --git a/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/ProfileFragment.java b/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/ProfileFragment.java index b6cfce8..6f1c334 100644 --- a/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/ProfileFragment.java +++ b/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/ProfileFragment.java @@ -37,8 +37,9 @@ import static android.app.Activity.RESULT_OK; public class ProfileFragment extends Fragment implements View.OnClickListener { static final int REQUEST_TAKE_PHOTO = 1; + ProgressDialog progressDialog; - /// Views, buttons and other protected declarations /// + /* Views, buttons and other protected and private inits */ protected Button changePwdButton; protected ImageButton profilePicButton; protected StorageReference httpsReference; @@ -46,17 +47,19 @@ public class ProfileFragment extends Fragment implements View.OnClickListener { protected ImageView profilePicture; protected FirebaseUser user; protected File photoFile; + private ListView listView; private DownloadClass downloadClass; private View headerInflater; private View timeLineInflater; - ProgressDialog progressDialog; - - /// Required empty public constructor /// - + /* Required empty public constructor */ public ProfileFragment() {} + /** + * Overridden onCreate which initializes a user and sets the default photoFile to null. + * @param savedInstanceState The standard return of the onCreate method. + */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -75,6 +78,9 @@ public class ProfileFragment extends Fragment implements View.OnClickListener { bindOnClick(); } + /** + * Assign the ListView and add the header to it. + */ protected void findTimelineViews() { listView = (ListView) timeLineInflater.findViewById(R.id.list); listView.addHeaderView(headerInflater); @@ -88,8 +94,15 @@ public class ProfileFragment extends Fragment implements View.OnClickListener { changePwdButton.setOnClickListener(this); } - /// Page setup /// - + /** + * Overridden onCreateView which serves as a fragment content creator. + * Checks for user data to be displayed. + * + * @param inflater The inflater used for the fragment. + * @param container The container which holds this fragment. + * @param savedInstanceState The state which was provided by onCreate. + * @return the timeLineInflater View which is required for the ListView to be updated. + */ @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { @@ -123,11 +136,11 @@ public class ProfileFragment extends Fragment implements View.OnClickListener { /** * Called when a view has been clicked. * - * @param v The view that was clicked. + * @param view The view that was clicked. */ @Override - public void onClick(View v) { - switch (v.getId()) { + public void onClick(View view) { + switch (view.getId()) { case R.id.profile_pic_button: profilePicOnClick(); break; @@ -142,13 +155,13 @@ public class ProfileFragment extends Fragment implements View.OnClickListener { */ private void profilePicOnClick() { Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); - /* Ensure that there's a camera activity to handle the intent */ + if (takePictureIntent.resolveActivity(getActivity().getPackageManager()) != null) { - /* Create the File where the photo should go */ try { photoFile = createImageFile(); } catch (IOException ex) { - Toast.makeText(getActivity(), getString(R.string.image_save_error), Toast.LENGTH_LONG).show(); + Toast.makeText(getActivity(), getString(R.string.image_save_error), + Toast.LENGTH_LONG).show(); } if (photoFile != null) { Uri photoURI = FileProvider.getUriForFile(getActivity(), @@ -160,6 +173,9 @@ public class ProfileFragment extends Fragment implements View.OnClickListener { } } + /** + * Start display of the list; uses an adapter and listener in the main activity. + */ public void startList() { ProfileAdapter adapter = new ProfileAdapter(getActivity(), downloadClass.getOwnPosts()); listView.setAdapter(adapter); @@ -167,6 +183,7 @@ public class ProfileFragment extends Fragment implements View.OnClickListener { /** * Grabs the image just taken by the built-in camera and pushes this image to the user account. + * * @param requestCode The code which corresponds to REQUEST_TAKE_PHOTO. Used as indicator. * @param resultCode Code should be RESULT_OK to allow camera to proceed. * @param data The image data from the camera. @@ -180,8 +197,13 @@ public class ProfileFragment extends Fragment implements View.OnClickListener { } } + /** + * Create the file which the camera requires to save a proper quality picture to. + * + * @return The new file. + * @throws IOException when insufficient permission or storage available. + */ private File createImageFile() throws IOException { - // Create an image file name String imageFileName = "JPEG_" + user.getUid(); File storageDir = getActivity().getExternalFilesDir(Environment.DIRECTORY_PICTURES); return File.createTempFile( @@ -191,9 +213,6 @@ public class ProfileFragment extends Fragment implements View.OnClickListener { ); } - - - // TODO Make this function into its own class for modularity. /** * Performs password reset action. */ @@ -209,8 +228,6 @@ public class ProfileFragment extends Fragment implements View.OnClickListener { Toast.LENGTH_SHORT).show(); } }); - } else { - // TODO Add code here for when there is no currently active user. } } } diff --git a/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/TimelineFragment.java b/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/TimelineFragment.java index 7d41818..c25cc55 100644 --- a/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/TimelineFragment.java +++ b/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/TimelineFragment.java @@ -1,6 +1,7 @@ package nl.myhyvesbookplus.tagram; import android.app.Fragment; +import android.app.ProgressDialog; import android.os.Bundle; import android.os.Handler; import android.support.v4.widget.SwipeRefreshLayout; @@ -9,27 +10,48 @@ import android.view.View; import android.view.ViewGroup; import android.widget.AbsListView; import android.widget.ListView; - - +import android.widget.Toast; import nl.myhyvesbookplus.tagram.controller.DownloadClass; public class TimelineFragment extends Fragment { + /* Some protected and private inits */ private ListView listView; private DownloadClass downloadClass; + ProgressDialog progressDialog; - public TimelineFragment() { - // Required empty public constructor + /* Required empty public constructor */ + public TimelineFragment() {} + + /** + * Overridden onCreate which also starts a progress dialog for the posts being downloaded. + * @param savedInstanceState The standard return of the onCreate method. + */ + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + progressDialog = ProgressDialog.show(getActivity(), getString(R.string.please_wait), getString(R.string.downloading_posts), false, false); } + /** + * Overridden onCreateView method which creates the ListView and contains a possible refresh + * functionality (swipe down page for result). + * + * https://www.survivingwithandroid.com/2014/05/android-swiperefreshlayout-tutorial-2.html + * Above reference was largely copied from. + * @param inflater The inflater used for the fragment. + * @param container The container which holds this fragment. + * @param savedInstanceState The state which was provided by onCreate. + * @return the timeLineInflater View which is required for the ListView to be updated. + */ @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.fragment_timeline, container, false); - listView = (ListView) view.findViewById(R.id.list); - final SwipeRefreshLayout swipeView = (SwipeRefreshLayout) view.findViewById(R.id.swipe); + View timeLineInflater = inflater.inflate(R.layout.fragment_timeline, container, false); + listView = (ListView) timeLineInflater.findViewById(R.id.list); + final SwipeRefreshLayout swipeView = (SwipeRefreshLayout) timeLineInflater.findViewById(R.id.swipe); swipeView.setEnabled(false); downloadClass = new DownloadClass(getActivity()); @@ -38,15 +60,16 @@ public class TimelineFragment extends Fragment { swipeView.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { @Override public void onRefresh() { - downloadClass = new DownloadClass(getActivity()); downloadClass.getPostsFromServer(); + Toast.makeText(getActivity(), R.string.refreshing, + Toast.LENGTH_LONG).show(); swipeView.setRefreshing(true); ( new Handler()).postDelayed(new Runnable() { @Override public void run() { swipeView.setRefreshing(false); } - }, 3000); + }, 1000); } }); @@ -57,15 +80,15 @@ public class TimelineFragment extends Fragment { @Override public void onScroll(AbsListView absListView, int firstVisibleItem, int visibleItemCount, int totalItemCount) { - if (firstVisibleItem == 0) - swipeView.setEnabled(true); - else - swipeView.setEnabled(false); + swipeView.setEnabled(firstVisibleItem == 0); } }); - return view; + return timeLineInflater; } + /** + * Start display of the list; uses an adapter and listener in the main activity. + */ public void startList() { TimeLineAdapter adapter = new TimeLineAdapter(getActivity(), downloadClass.getmList()); listView.setAdapter(adapter); diff --git a/app/MyHyvesBookPlusStagram/app/src/main/res/values-nl/strings.xml b/app/MyHyvesBookPlusStagram/app/src/main/res/values-nl/strings.xml index f02108c..f14844b 100644 --- a/app/MyHyvesBookPlusStagram/app/src/main/res/values-nl/strings.xml +++ b/app/MyHyvesBookPlusStagram/app/src/main/res/values-nl/strings.xml @@ -11,15 +11,12 @@ Tijdlijn Profiel Gebruikersnaam - bevestig wachtwoord MyHyvesBookPlusTagram logo Uitloggen Wijzig Profiel Foto profiel foto Wachtwoord wijzigen Momentje - Hallo leeg fragment - Hallo Camera fragment Voer alstublieft email en wachtwoord in Er is een fout opgetreden. Controleer internetverbinding. Er is een e-mail verzonden. Volg a.u.b. de instructies. @@ -30,9 +27,12 @@ Foto opslaan mislukt. Zorg a.u.b. dat er genoeg ruimte op uw telefoon beschikbaar is. Het updaten van de profielfoto is mislukt. Controleer uw internetverbinding. Profielfoto aan het uploaden… - An e-mail was sent, please follow its instructions. Niet Slecht. Bijschrift: Annuleer Hallo Ik ben een comment! + Verversen… + Posts worden gedownload… + Aan het inloggen + Aan het registreren \ No newline at end of file diff --git a/app/MyHyvesBookPlusStagram/app/src/main/res/values/strings.xml b/app/MyHyvesBookPlusStagram/app/src/main/res/values/strings.xml index afa90b1..3e4425c 100644 --- a/app/MyHyvesBookPlusStagram/app/src/main/res/values/strings.xml +++ b/app/MyHyvesBookPlusStagram/app/src/main/res/values/strings.xml @@ -6,7 +6,6 @@ Username Password Confirm Password - confirm password Login Register back to Login @@ -14,8 +13,6 @@ Please fill in email and password Passwords do not match Please fill in all the fields - Hello blank fragment - Hello Camera MyHyvesBookPlusTagram logo Logout Change Profile Picture @@ -33,5 +30,8 @@ Comment: Cancel Hello, I am a comment! - Er is een e-mail verzonden. Volg a.u.b. de instructies. + Refreshing… + Downloading posts… + Registering + Logging in -- 2.49.1 From 4eed601b7d4e43bdd174c6515dc06f2bd8d7cad8 Mon Sep 17 00:00:00 2001 From: Niels Zwemmer Date: Thu, 29 Jun 2017 12:50:29 +0200 Subject: [PATCH 05/22] WIP: for Felix --- .../tagram/CameraFragment.java | 15 ++++----- .../myhyvesbookplus/tagram/MainActivity.java | 2 +- .../tagram/ProfileFragment.java | 2 ++ .../tagram/TimelineFragment.java | 13 +++++++- .../src/main/res/layout/fragment_timeline.xml | 31 +++++++++++++------ 5 files changed, 43 insertions(+), 20 deletions(-) diff --git a/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/CameraFragment.java b/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/CameraFragment.java index ab95c27..575b956 100644 --- a/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/CameraFragment.java +++ b/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/CameraFragment.java @@ -39,11 +39,11 @@ public class CameraFragment extends Fragment implements PostUploader.PostUploadL public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Inflate the layout for this fragment - ((AppCompatActivity)getActivity()).getSupportActionBar().hide(); - getActivity().findViewById(R.id.content).setPadding(0,0,0,0); - final View view = inflater.inflate(R.layout.fragment_camera, container, false); + // Hide the action bar + ((AppCompatActivity)getActivity()).getSupportActionBar().hide(); + mCamera = getCameraInstance(facing); mPreview = new CameraPreview(getActivity().getBaseContext(), mCamera); @@ -217,16 +217,13 @@ public class CameraFragment extends Fragment implements PostUploader.PostUploadL .toggleSoftInput(InputMethodManager.SHOW_IMPLICIT, 0); } - //TODO Niet helemaal zeker wat dit doet. + /** + * Restores the action bar when exiting the fragment. + */ @Override public void onDestroyView() { super.onDestroyView(); - - int padding = 16; - float scale = getResources().getDisplayMetrics().density; - int dp = (int) (padding * scale + 0.5f); ((AppCompatActivity)getActivity()).getSupportActionBar().show(); - getActivity().findViewById(R.id.content).setPadding(dp,dp,dp,dp); } /** diff --git a/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/MainActivity.java b/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/MainActivity.java index 28b3a6d..993d195 100644 --- a/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/MainActivity.java +++ b/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/MainActivity.java @@ -123,7 +123,7 @@ public class MainActivity extends AppCompatActivity implements if (frag instanceof ProfileFragment) { ((ProfileFragment) frag).startList(); } else if (frag instanceof TimelineFragment) { - ((TimelineFragment) frag).progressDialog.dismiss(); +// ((TimelineFragment) frag).progressDialog.dismiss(); ((TimelineFragment) frag).startList(); } } diff --git a/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/ProfileFragment.java b/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/ProfileFragment.java index 6f1c334..0b88e92 100644 --- a/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/ProfileFragment.java +++ b/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/ProfileFragment.java @@ -16,6 +16,7 @@ import android.widget.Button; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.ListView; +import android.widget.ProgressBar; import android.widget.TextView; import android.widget.Toast; import com.bumptech.glide.Glide; @@ -38,6 +39,7 @@ import static android.app.Activity.RESULT_OK; public class ProfileFragment extends Fragment implements View.OnClickListener { static final int REQUEST_TAKE_PHOTO = 1; ProgressDialog progressDialog; + ProgressBar progressBar; /* Views, buttons and other protected and private inits */ protected Button changePwdButton; diff --git a/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/TimelineFragment.java b/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/TimelineFragment.java index c25cc55..f545bd4 100644 --- a/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/TimelineFragment.java +++ b/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/TimelineFragment.java @@ -5,11 +5,13 @@ import android.app.ProgressDialog; import android.os.Bundle; import android.os.Handler; import android.support.v4.widget.SwipeRefreshLayout; +import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.AbsListView; import android.widget.ListView; +import android.widget.ProgressBar; import android.widget.Toast; import nl.myhyvesbookplus.tagram.controller.DownloadClass; @@ -21,6 +23,7 @@ public class TimelineFragment extends Fragment { private ListView listView; private DownloadClass downloadClass; ProgressDialog progressDialog; + ProgressBar progressBar; /* Required empty public constructor */ public TimelineFragment() {} @@ -32,7 +35,7 @@ public class TimelineFragment extends Fragment { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - progressDialog = ProgressDialog.show(getActivity(), getString(R.string.please_wait), getString(R.string.downloading_posts), false, false); +// progressDialog = ProgressDialog.show(getActivity(), getString(R.string.please_wait), getString(R.string.downloading_posts), false, false); } /** @@ -50,6 +53,13 @@ public class TimelineFragment extends Fragment { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View timeLineInflater = inflater.inflate(R.layout.fragment_timeline, container, false); + +// progressBar = new ProgressBar(getActivity()); + Log.d("TIMELINEFRAGMENT", "onCreateView: PROGRESSBAR"); + progressBar = (ProgressBar) timeLineInflater.findViewById(R.id.progressbar_timeline); + progressBar.setVisibility(View.VISIBLE); + progressBar.bringToFront(); + listView = (ListView) timeLineInflater.findViewById(R.id.list); final SwipeRefreshLayout swipeView = (SwipeRefreshLayout) timeLineInflater.findViewById(R.id.swipe); @@ -83,6 +93,7 @@ public class TimelineFragment extends Fragment { swipeView.setEnabled(firstVisibleItem == 0); } }); + progressBar.setVisibility(View.GONE); return timeLineInflater; } diff --git a/app/MyHyvesBookPlusStagram/app/src/main/res/layout/fragment_timeline.xml b/app/MyHyvesBookPlusStagram/app/src/main/res/layout/fragment_timeline.xml index 4c91e9e..68e3085 100644 --- a/app/MyHyvesBookPlusStagram/app/src/main/res/layout/fragment_timeline.xml +++ b/app/MyHyvesBookPlusStagram/app/src/main/res/layout/fragment_timeline.xml @@ -5,19 +5,32 @@ android:orientation="vertical" tools:context="nl.myhyvesbookplus.tagram.TimelineFragment"> - + android:layout_height="match_parent"> - + + - - + + + + + + -- 2.49.1 From 7936350ede3f54593066bcff6ca9a0e83531249d Mon Sep 17 00:00:00 2001 From: Marijn Jansen Date: Thu, 29 Jun 2017 13:35:49 +0200 Subject: [PATCH 06/22] Fix! --- .../java/nl/myhyvesbookplus/tagram/TimeLineAdapter.java | 6 ------ 1 file changed, 6 deletions(-) diff --git a/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/TimeLineAdapter.java b/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/TimeLineAdapter.java index 8146347..8282574 100644 --- a/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/TimeLineAdapter.java +++ b/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/TimeLineAdapter.java @@ -8,22 +8,16 @@ import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.BaseAdapter; -import android.widget.Button; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.TextView; import com.bumptech.glide.Glide; import com.firebase.ui.storage.images.FirebaseImageLoader; -<<<<<<< HEAD import com.google.android.gms.tasks.OnCompleteListener; import com.google.android.gms.tasks.Task; import com.google.firebase.database.DatabaseReference; import com.google.firebase.database.FirebaseDatabase; -======= -import com.google.firebase.auth.FirebaseAuth; -import com.google.firebase.auth.FirebaseUser; ->>>>>>> origin/master import com.google.firebase.storage.FirebaseStorage; import com.google.firebase.storage.StorageReference; -- 2.49.1 From bd4149ccb19edf3eb4e002a1807d9b9a59d437be Mon Sep 17 00:00:00 2001 From: Niels Zwemmer Date: Thu, 29 Jun 2017 13:41:23 +0200 Subject: [PATCH 07/22] Added rotate restriction. Merge-prep with Felix. --- app/MyHyvesBookPlusStagram/app/src/main/AndroidManifest.xml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/MyHyvesBookPlusStagram/app/src/main/AndroidManifest.xml b/app/MyHyvesBookPlusStagram/app/src/main/AndroidManifest.xml index 2284c0c..23c8670 100644 --- a/app/MyHyvesBookPlusStagram/app/src/main/AndroidManifest.xml +++ b/app/MyHyvesBookPlusStagram/app/src/main/AndroidManifest.xml @@ -26,6 +26,7 @@ @@ -34,7 +35,9 @@ - + -- 2.49.1 From c38cc026fc5756ccb5996337ab96eb1457718a1e Mon Sep 17 00:00:00 2001 From: Felix Atsma Date: Thu, 29 Jun 2017 13:42:44 +0200 Subject: [PATCH 08/22] Add progress bar for timeline --- .../nl/myhyvesbookplus/tagram/ProfileFragment.java | 4 ++-- .../nl/myhyvesbookplus/tagram/TimelineFragment.java | 13 ++----------- 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/ProfileFragment.java b/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/ProfileFragment.java index 0b88e92..465a08a 100644 --- a/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/ProfileFragment.java +++ b/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/ProfileFragment.java @@ -16,7 +16,6 @@ import android.widget.Button; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.ListView; -import android.widget.ProgressBar; import android.widget.TextView; import android.widget.Toast; import com.bumptech.glide.Glide; @@ -39,7 +38,6 @@ import static android.app.Activity.RESULT_OK; public class ProfileFragment extends Fragment implements View.OnClickListener { static final int REQUEST_TAKE_PHOTO = 1; ProgressDialog progressDialog; - ProgressBar progressBar; /* Views, buttons and other protected and private inits */ protected Button changePwdButton; @@ -233,3 +231,5 @@ public class ProfileFragment extends Fragment implements View.OnClickListener { } } } + + diff --git a/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/TimelineFragment.java b/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/TimelineFragment.java index f545bd4..b4d56d8 100644 --- a/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/TimelineFragment.java +++ b/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/TimelineFragment.java @@ -1,11 +1,9 @@ package nl.myhyvesbookplus.tagram; import android.app.Fragment; -import android.app.ProgressDialog; import android.os.Bundle; import android.os.Handler; import android.support.v4.widget.SwipeRefreshLayout; -import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -22,20 +20,17 @@ public class TimelineFragment extends Fragment { /* Some protected and private inits */ private ListView listView; private DownloadClass downloadClass; - ProgressDialog progressDialog; - ProgressBar progressBar; + private ProgressBar progressBar; /* Required empty public constructor */ public TimelineFragment() {} /** - * Overridden onCreate which also starts a progress dialog for the posts being downloaded. * @param savedInstanceState The standard return of the onCreate method. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); -// progressDialog = ProgressDialog.show(getActivity(), getString(R.string.please_wait), getString(R.string.downloading_posts), false, false); } /** @@ -53,12 +48,8 @@ public class TimelineFragment extends Fragment { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View timeLineInflater = inflater.inflate(R.layout.fragment_timeline, container, false); - -// progressBar = new ProgressBar(getActivity()); - Log.d("TIMELINEFRAGMENT", "onCreateView: PROGRESSBAR"); progressBar = (ProgressBar) timeLineInflater.findViewById(R.id.progressbar_timeline); progressBar.setVisibility(View.VISIBLE); - progressBar.bringToFront(); listView = (ListView) timeLineInflater.findViewById(R.id.list); final SwipeRefreshLayout swipeView = (SwipeRefreshLayout) timeLineInflater.findViewById(R.id.swipe); @@ -93,7 +84,6 @@ public class TimelineFragment extends Fragment { swipeView.setEnabled(firstVisibleItem == 0); } }); - progressBar.setVisibility(View.GONE); return timeLineInflater; } @@ -103,5 +93,6 @@ public class TimelineFragment extends Fragment { public void startList() { TimeLineAdapter adapter = new TimeLineAdapter(getActivity(), downloadClass.getmList()); listView.setAdapter(adapter); + progressBar.setVisibility(View.GONE); } } -- 2.49.1 From 9d016b8c6509882e7aca2d509813e8ed4b6efd44 Mon Sep 17 00:00:00 2001 From: Niels Zwemmer Date: Thu, 29 Jun 2017 14:01:27 +0200 Subject: [PATCH 09/22] Added a progressBar to the profilepage aswell. --- .../tagram/ProfileFragment.java | 5 +++++ .../res/layout/fragment_profile_timeline.xml | 21 ++++++++++++++++--- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/ProfileFragment.java b/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/ProfileFragment.java index 465a08a..43493f4 100644 --- a/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/ProfileFragment.java +++ b/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/ProfileFragment.java @@ -16,6 +16,7 @@ import android.widget.Button; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.ListView; +import android.widget.ProgressBar; import android.widget.TextView; import android.widget.Toast; import com.bumptech.glide.Glide; @@ -52,6 +53,7 @@ public class ProfileFragment extends Fragment implements View.OnClickListener { private DownloadClass downloadClass; private View headerInflater; private View timeLineInflater; + private ProgressBar progressBar; /* Required empty public constructor */ public ProfileFragment() {} @@ -109,6 +111,8 @@ public class ProfileFragment extends Fragment implements View.OnClickListener { timeLineInflater = inflater.inflate(R.layout.fragment_profile_timeline, container, false); headerInflater = inflater.inflate(R.layout.fragment_profile_header, listView, false); + progressBar = (ProgressBar) timeLineInflater.findViewById(R.id.progressbar_timeline); + progressBar.setVisibility(View.VISIBLE); findHeaderViews(); findTimelineViews(); @@ -179,6 +183,7 @@ public class ProfileFragment extends Fragment implements View.OnClickListener { public void startList() { ProfileAdapter adapter = new ProfileAdapter(getActivity(), downloadClass.getOwnPosts()); listView.setAdapter(adapter); + progressBar.setVisibility(View.GONE); } /** diff --git a/app/MyHyvesBookPlusStagram/app/src/main/res/layout/fragment_profile_timeline.xml b/app/MyHyvesBookPlusStagram/app/src/main/res/layout/fragment_profile_timeline.xml index 523ff58..ea8dc3c 100644 --- a/app/MyHyvesBookPlusStagram/app/src/main/res/layout/fragment_profile_timeline.xml +++ b/app/MyHyvesBookPlusStagram/app/src/main/res/layout/fragment_profile_timeline.xml @@ -5,9 +5,24 @@ android:orientation="vertical" tools:context="nl.myhyvesbookplus.tagram.TimelineFragment"> - - + + + + + + + + \ No newline at end of file -- 2.49.1 From d8c04c78eacdd9d9f63335edb0334c568cabddc9 Mon Sep 17 00:00:00 2001 From: Felix Atsma Date: Thu, 29 Jun 2017 14:32:03 +0200 Subject: [PATCH 10/22] Fix keyboard hiding crash + prettify findviewbyid's in camerafragment --- .../tagram/CameraFragment.java | 58 ++++++++----------- .../src/main/res/layout/fragment_camera.xml | 8 --- 2 files changed, 23 insertions(+), 43 deletions(-) diff --git a/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/CameraFragment.java b/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/CameraFragment.java index 575b956..58511ba 100644 --- a/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/CameraFragment.java +++ b/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/CameraFragment.java @@ -1,13 +1,10 @@ package nl.myhyvesbookplus.tagram; import android.app.Activity; -import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.hardware.Camera; import android.hardware.Camera.PictureCallback; -import android.media.Image; -import android.net.Uri; import android.os.Bundle; import android.app.Fragment; import android.support.design.widget.FloatingActionButton; @@ -19,6 +16,7 @@ import android.view.ViewGroup; import android.view.inputmethod.InputMethodManager; import android.widget.EditText; import android.widget.ImageButton; +import android.widget.LinearLayout; import android.widget.RelativeLayout; import nl.myhyvesbookplus.tagram.controller.PostUploader; @@ -31,9 +29,8 @@ public class CameraFragment extends Fragment implements PostUploader.PostUploadL private Bitmap mPhoto; private int facing = Camera.CameraInfo.CAMERA_FACING_BACK; - public CameraFragment() { - // Required empty public constructor - } + /* Required empty public constructor */ + public CameraFragment() { } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, @@ -41,24 +38,28 @@ public class CameraFragment extends Fragment implements PostUploader.PostUploadL // Inflate the layout for this fragment final View view = inflater.inflate(R.layout.fragment_camera, container, false); + final RelativeLayout filterButtons = (RelativeLayout) view.findViewById(R.id.filter_buttons); + final RelativeLayout mCameraLayout = (RelativeLayout) view.findViewById(R.id.camera_preview); + final LinearLayout commentBox = (LinearLayout) view.findViewById(R.id.comment_box); + final ImageButton pictureButton = (ImageButton) view.findViewById(R.id.picture_button); + final ImageButton switchButton = (ImageButton) view.findViewById(R.id.switch_camera_button); + // Hide the action bar ((AppCompatActivity)getActivity()).getSupportActionBar().hide(); mCamera = getCameraInstance(facing); mPreview = new CameraPreview(getActivity().getBaseContext(), mCamera); - final RelativeLayout filterButtons = (RelativeLayout) view.findViewById(R.id.filter_buttons); - final RelativeLayout mCameraLayout = (RelativeLayout) view.findViewById(R.id.camera_preview); mCameraLayout.addView(mPreview); // Draw initial buttons over preview - view.findViewById(R.id.picture_button).bringToFront(); - view.findViewById(R.id.switch_camera_button).bringToFront(); + pictureButton.bringToFront(); + switchButton.bringToFront(); filterButtons.bringToFront(); /* Upon pressing the switch camera facing button: */ - (view.findViewById(R.id.switch_camera_button)).setOnClickListener(new View.OnClickListener() { + switchButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { switchFacing(); @@ -69,13 +70,13 @@ public class CameraFragment extends Fragment implements PostUploader.PostUploadL mPreview = new CameraPreview(getActivity().getBaseContext(), mCamera); mCameraLayout.addView(mPreview); - view.findViewById(R.id.picture_button).bringToFront(); - view.findViewById(R.id.switch_camera_button).bringToFront(); + pictureButton.bringToFront(); + switchButton.bringToFront(); } }); /* Upon pressing the take photo button: */ - (view.findViewById(R.id.picture_button)).setOnClickListener(new View.OnClickListener() { + pictureButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mCamera.takePicture(null, null, new PictureCallback() { @@ -101,12 +102,11 @@ public class CameraFragment extends Fragment implements PostUploader.PostUploadL (view.findViewById(R.id.upload_button)).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - view.findViewById(R.id.comment_box).setClickable(true); - view.findViewById(R.id.comment_box).setVisibility(View.VISIBLE); - view.findViewById(R.id.comment_box).bringToFront(); - view.findViewById(R.id.filter_buttons).setVisibility(View.GONE); + commentBox.setClickable(true); + commentBox.setVisibility(View.VISIBLE); + commentBox.bringToFront(); + filterButtons.setVisibility(View.GONE); ((FloatingActionButton)view.findViewById(R.id.upload_button)).hide(); - hideKeyboard(); } }); @@ -134,8 +134,8 @@ public class CameraFragment extends Fragment implements PostUploader.PostUploadL mPreview = new CameraPreview(getActivity().getBaseContext(), mCamera); mCameraLayout.addView(mPreview); - view.findViewById(R.id.picture_button).bringToFront(); - view.findViewById(R.id.switch_camera_button).bringToFront(); + pictureButton.bringToFront(); + switchButton.bringToFront(); mCameraLayout.removeView(view.findViewById(R.id.pic_preview)); hideKeyboard(); @@ -160,8 +160,8 @@ public class CameraFragment extends Fragment implements PostUploader.PostUploadL mPreview = new CameraPreview(getActivity().getBaseContext(), mCamera); mCameraLayout.addView(mPreview); - view.findViewById(R.id.picture_button).bringToFront(); - view.findViewById(R.id.switch_camera_button).bringToFront(); + pictureButton.bringToFront(); + switchButton.bringToFront(); mCameraLayout.removeView(view.findViewById(R.id.pic_preview)); hideKeyboard(); @@ -286,18 +286,6 @@ public class CameraFragment extends Fragment implements PostUploader.PostUploadL } } - - //TODO: Kan dit weg? super aanroepen enzo. - @Override - public void onPause() { - super.onPause(); - } - - @Override - public void onResume() { - super.onResume(); - } - @Override public void PostUploadComplete(Boolean success) { diff --git a/app/MyHyvesBookPlusStagram/app/src/main/res/layout/fragment_camera.xml b/app/MyHyvesBookPlusStagram/app/src/main/res/layout/fragment_camera.xml index 9815205..9470c2a 100644 --- a/app/MyHyvesBookPlusStagram/app/src/main/res/layout/fragment_camera.xml +++ b/app/MyHyvesBookPlusStagram/app/src/main/res/layout/fragment_camera.xml @@ -36,14 +36,6 @@ android:background="@android:color/transparent" android:src="@drawable/ic_switch_camera_black_24dp"/> - - Date: Thu, 29 Jun 2017 15:18:12 +0200 Subject: [PATCH 11/22] added animation --- .../tagram/ProfileAdapter.java | 154 +++++++++++++++++- .../tagram/TimeLineAdapter.java | 154 +++++++++++++++++- .../res/layout/fragment_profile_timeline.xml | 11 +- .../src/main/res/layout/fragment_timeline.xml | 10 +- 4 files changed, 322 insertions(+), 7 deletions(-) diff --git a/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/ProfileAdapter.java b/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/ProfileAdapter.java index 357876a..0535f55 100644 --- a/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/ProfileAdapter.java +++ b/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/ProfileAdapter.java @@ -1,15 +1,22 @@ package nl.myhyvesbookplus.tagram; import android.content.Context; +import android.graphics.Point; +import android.graphics.Rect; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.view.animation.DecelerateInterpolator; import android.widget.BaseAdapter; import android.widget.Button; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.ListView; import android.widget.TextView; +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; import com.bumptech.glide.Glide; import com.firebase.ui.storage.images.FirebaseImageLoader; @@ -33,6 +40,7 @@ public class ProfileAdapter extends BaseAdapter { private TextView comment; private TextView nietSlechts; private ImageView photo; + private Animator mCurrentAnimator; ProfileAdapter(Context context, ArrayList data) { mContext = context; @@ -61,12 +69,19 @@ public class ProfileAdapter extends BaseAdapter { View newRowView = findViews(rowView); UriPost post = (UriPost) getItem(position); comment.setText(post.getComment()); - StorageReference ref = FirebaseStorage.getInstance().getReferenceFromUrl(post.getUri()); + final StorageReference ref = FirebaseStorage.getInstance().getReferenceFromUrl(post.getUri()); Glide.with(mContext) .using(new FirebaseImageLoader()) .load(ref) .into(photo); + photo.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + zoomImageFromThumb(photo, ref); + } + }); + return newRowView; } @@ -76,4 +91,141 @@ public class ProfileAdapter extends BaseAdapter { photo = (ImageView) rowView.findViewById(R.id.timeline_image_profile); return rowView; } + + /** + * https://developer.android.com/training/animation/zoom.html + * "Zooms" in a thumbnail view by assigning the high resolution image to a hidden "zoomed-in" + * image view and animating its bounds to fit the entire activity content area. + * + * @param thumbView The thumbnail view to zoom in. + * @param imageRef The high-resolution version of the image represented by the thumbnail. + */ + private void zoomImageFromThumb(final View thumbView, StorageReference imageRef) { + // If there's an animation in progress, cancel it immediately and proceed with this one. + if (mCurrentAnimator != null) { + mCurrentAnimator.cancel(); + } + + // Load the high-resolution "zoomed-in" image. + final ImageView hiddenView = (ImageView) ((MainActivity) mContext).findViewById(R.id.expanded_image_profile); + + Glide.with(mContext) + .using(new FirebaseImageLoader()) + .load(imageRef) + .into(hiddenView); + + // Calculate the starting and ending bounds for the zoomed-in image. This step + // involves lots of math. Yay, math. + final Rect startBounds = new Rect(); + final Rect finalBounds = new Rect(); + final Point globalOffset = new Point(); + + // The start bounds are the global visible rectangle of the thumbnail, and the + // final bounds are the global visible rectangle of the container view. Also + // set the container view's offset as the origin for the bounds, since that's + // the origin for the positioning animation properties (X, Y). + thumbView.getGlobalVisibleRect(startBounds); + ((MainActivity) mContext).findViewById(R.id.relative_layout_timeline_profile).getGlobalVisibleRect(finalBounds, globalOffset); + startBounds.offset(-globalOffset.x, -globalOffset.y); + finalBounds.offset(-globalOffset.x, -globalOffset.y); + + // Adjust the start bounds to be the same aspect ratio as the final bounds using the + // "center crop" technique. This prevents undesirable stretching during the animation. + // Also calculate the start scaling factor (the end scaling factor is always 1.0). + float startScale; + if ((float) finalBounds.width() / finalBounds.height() + > (float) startBounds.width() / startBounds.height()) { + // Extend start bounds horizontally + startScale = (float) startBounds.height() / finalBounds.height(); + float startWidth = startScale * finalBounds.width(); + float deltaWidth = (startWidth - startBounds.width()) / 2; + startBounds.left -= deltaWidth; + startBounds.right += deltaWidth; + } else { + // Extend start bounds vertically + startScale = (float) startBounds.width() / finalBounds.width(); + float startHeight = startScale * finalBounds.height(); + float deltaHeight = (startHeight - startBounds.height()) / 2; + startBounds.top -= deltaHeight; + startBounds.bottom += deltaHeight; + } + + // Hide the thumbnail and show the zoomed-in view. When the animation begins, + // it will position the zoomed-in view in the place of the thumbnail. + thumbView.setAlpha(0f); + hiddenView.setVisibility(View.VISIBLE); + + // Set the pivot point for SCALE_X and SCALE_Y transformations to the top-left corner of + // the zoomed-in view (the default is the center of the view). + hiddenView.setPivotX(0f); + hiddenView.setPivotY(0f); + + // Construct and run the parallel animation of the four translation and scale properties + // (X, Y, SCALE_X, and SCALE_Y). + AnimatorSet set = new AnimatorSet(); + set + .play(ObjectAnimator.ofFloat(hiddenView, View.X, startBounds.left, + finalBounds.left)) + .with(ObjectAnimator.ofFloat(hiddenView, View.Y, startBounds.top, + finalBounds.top)) + .with(ObjectAnimator.ofFloat(hiddenView, View.SCALE_X, startScale, 1f)) + .with(ObjectAnimator.ofFloat(hiddenView, View.SCALE_Y, startScale, 1f)); + set.setDuration(200); + set.setInterpolator(new DecelerateInterpolator()); + set.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + mCurrentAnimator = null; + } + + @Override + public void onAnimationCancel(Animator animation) { + mCurrentAnimator = null; + } + }); + set.start(); + mCurrentAnimator = set; + + // Upon clicking the zoomed-in image, it should zoom back down to the original bounds + // and show the thumbnail instead of the expanded image. + final float startScaleFinal = startScale; + hiddenView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + if (mCurrentAnimator != null) { + mCurrentAnimator.cancel(); + } + + // Animate the four positioning/sizing properties in parallel, back to their + // original values. + AnimatorSet set = new AnimatorSet(); + set + .play(ObjectAnimator.ofFloat(hiddenView, View.X, startBounds.left)) + .with(ObjectAnimator.ofFloat(hiddenView, View.Y, startBounds.top)) + .with(ObjectAnimator + .ofFloat(hiddenView, View.SCALE_X, startScaleFinal)) + .with(ObjectAnimator + .ofFloat(hiddenView, View.SCALE_Y, startScaleFinal)); + set.setDuration(200); + set.setInterpolator(new DecelerateInterpolator()); + set.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + thumbView.setAlpha(1f); + hiddenView.setVisibility(View.GONE); + mCurrentAnimator = null; + } + + @Override + public void onAnimationCancel(Animator animation) { + thumbView.setAlpha(1f); + hiddenView.setVisibility(View.GONE); + mCurrentAnimator = null; + } + }); + set.start(); + mCurrentAnimator = set; + } + }); + } } diff --git a/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/TimeLineAdapter.java b/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/TimeLineAdapter.java index 8282574..fb8c7ef 100644 --- a/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/TimeLineAdapter.java +++ b/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/TimeLineAdapter.java @@ -1,16 +1,23 @@ package nl.myhyvesbookplus.tagram; import android.content.Context; +import android.graphics.Point; +import android.graphics.Rect; import android.support.annotation.NonNull; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.view.animation.DecelerateInterpolator; import android.widget.AdapterView; import android.widget.BaseAdapter; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.TextView; +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; import com.bumptech.glide.Glide; import com.firebase.ui.storage.images.FirebaseImageLoader; @@ -35,6 +42,7 @@ public class TimeLineAdapter extends BaseAdapter implements AdapterView.OnItemCl private Context mContext; private ArrayList mData; private DatabaseReference mRef; + private Animator mCurrentAnimator; TimeLineAdapter(Context context, ArrayList data) { mContext = context; @@ -66,7 +74,7 @@ public class TimeLineAdapter extends BaseAdapter implements AdapterView.OnItemCl TextView comment = (TextView) rowView.findViewById(R.id.comment_timeline); final TextView nietSlechts = (TextView) rowView.findViewById(R.id.niet_slecht_count); TextView dateTime = (TextView) rowView.findViewById(R.id.timeline_date); - ImageView photo = (ImageView) rowView.findViewById(R.id.timeline_image); + final ImageView photo = (ImageView) rowView.findViewById(R.id.timeline_image); final ImageButton nietSlechtButton = (ImageButton) rowView.findViewById(R.id.niet_slecht_button); final UriPost post = (UriPost) getItem(position); @@ -91,12 +99,18 @@ public class TimeLineAdapter extends BaseAdapter implements AdapterView.OnItemCl dateTime.setText(post.getDate().toString()); - StorageReference ref = FirebaseStorage.getInstance().getReferenceFromUrl(post.getUri()); + final StorageReference ref = FirebaseStorage.getInstance().getReferenceFromUrl(post.getUri()); Glide.with(mContext) .using(new FirebaseImageLoader()) .load(ref) .into(photo); + photo.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + zoomImageFromThumb(photo, ref); + } + }); return rowView; } @@ -119,4 +133,140 @@ public class TimeLineAdapter extends BaseAdapter implements AdapterView.OnItemCl Log.d(TAG, "onItemClick: rowNumber! "+ position); } + /** + * https://developer.android.com/training/animation/zoom.html + * "Zooms" in a thumbnail view by assigning the high resolution image to a hidden "zoomed-in" + * image view and animating its bounds to fit the entire activity content area. + * + * @param thumbView The thumbnail view to zoom in. + * @param imageRef The high-resolution version of the image represented by the thumbnail. + */ + private void zoomImageFromThumb(final View thumbView, StorageReference imageRef) { + // If there's an animation in progress, cancel it immediately and proceed with this one. + if (mCurrentAnimator != null) { + mCurrentAnimator.cancel(); + } + + // Load the high-resolution "zoomed-in" image. + final ImageView hiddenView = (ImageView) ((MainActivity) mContext).findViewById(R.id.expanded_image); + + Glide.with(mContext) + .using(new FirebaseImageLoader()) + .load(imageRef) + .into(hiddenView); + + // Calculate the starting and ending bounds for the zoomed-in image. This step + // involves lots of math. Yay, math. + final Rect startBounds = new Rect(); + final Rect finalBounds = new Rect(); + final Point globalOffset = new Point(); + + // The start bounds are the global visible rectangle of the thumbnail, and the + // final bounds are the global visible rectangle of the container view. Also + // set the container view's offset as the origin for the bounds, since that's + // the origin for the positioning animation properties (X, Y). + thumbView.getGlobalVisibleRect(startBounds); + ((MainActivity) mContext).findViewById(R.id.relative_layout_timeline).getGlobalVisibleRect(finalBounds, globalOffset); + startBounds.offset(-globalOffset.x, -globalOffset.y); + finalBounds.offset(-globalOffset.x, -globalOffset.y); + + // Adjust the start bounds to be the same aspect ratio as the final bounds using the + // "center crop" technique. This prevents undesirable stretching during the animation. + // Also calculate the start scaling factor (the end scaling factor is always 1.0). + float startScale; + if ((float) finalBounds.width() / finalBounds.height() + > (float) startBounds.width() / startBounds.height()) { + // Extend start bounds horizontally + startScale = (float) startBounds.height() / finalBounds.height(); + float startWidth = startScale * finalBounds.width(); + float deltaWidth = (startWidth - startBounds.width()) / 2; + startBounds.left -= deltaWidth; + startBounds.right += deltaWidth; + } else { + // Extend start bounds vertically + startScale = (float) startBounds.width() / finalBounds.width(); + float startHeight = startScale * finalBounds.height(); + float deltaHeight = (startHeight - startBounds.height()) / 2; + startBounds.top -= deltaHeight; + startBounds.bottom += deltaHeight; + } + + // Hide the thumbnail and show the zoomed-in view. When the animation begins, + // it will position the zoomed-in view in the place of the thumbnail. + thumbView.setAlpha(0f); + hiddenView.setVisibility(View.VISIBLE); + + // Set the pivot point for SCALE_X and SCALE_Y transformations to the top-left corner of + // the zoomed-in view (the default is the center of the view). + hiddenView.setPivotX(0f); + hiddenView.setPivotY(0f); + + // Construct and run the parallel animation of the four translation and scale properties + // (X, Y, SCALE_X, and SCALE_Y). + AnimatorSet set = new AnimatorSet(); + set + .play(ObjectAnimator.ofFloat(hiddenView, View.X, startBounds.left, + finalBounds.left)) + .with(ObjectAnimator.ofFloat(hiddenView, View.Y, startBounds.top, + finalBounds.top)) + .with(ObjectAnimator.ofFloat(hiddenView, View.SCALE_X, startScale, 1f)) + .with(ObjectAnimator.ofFloat(hiddenView, View.SCALE_Y, startScale, 1f)); + set.setDuration(200); + set.setInterpolator(new DecelerateInterpolator()); + set.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + mCurrentAnimator = null; + } + + @Override + public void onAnimationCancel(Animator animation) { + mCurrentAnimator = null; + } + }); + set.start(); + mCurrentAnimator = set; + + // Upon clicking the zoomed-in image, it should zoom back down to the original bounds + // and show the thumbnail instead of the expanded image. + final float startScaleFinal = startScale; + hiddenView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + if (mCurrentAnimator != null) { + mCurrentAnimator.cancel(); + } + + // Animate the four positioning/sizing properties in parallel, back to their + // original values. + AnimatorSet set = new AnimatorSet(); + set + .play(ObjectAnimator.ofFloat(hiddenView, View.X, startBounds.left)) + .with(ObjectAnimator.ofFloat(hiddenView, View.Y, startBounds.top)) + .with(ObjectAnimator + .ofFloat(hiddenView, View.SCALE_X, startScaleFinal)) + .with(ObjectAnimator + .ofFloat(hiddenView, View.SCALE_Y, startScaleFinal)); + set.setDuration(200); + set.setInterpolator(new DecelerateInterpolator()); + set.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + thumbView.setAlpha(1f); + hiddenView.setVisibility(View.GONE); + mCurrentAnimator = null; + } + + @Override + public void onAnimationCancel(Animator animation) { + thumbView.setAlpha(1f); + hiddenView.setVisibility(View.GONE); + mCurrentAnimator = null; + } + }); + set.start(); + mCurrentAnimator = set; + } + }); + } } diff --git a/app/MyHyvesBookPlusStagram/app/src/main/res/layout/fragment_profile_timeline.xml b/app/MyHyvesBookPlusStagram/app/src/main/res/layout/fragment_profile_timeline.xml index fd06e94..56a00ad 100644 --- a/app/MyHyvesBookPlusStagram/app/src/main/res/layout/fragment_profile_timeline.xml +++ b/app/MyHyvesBookPlusStagram/app/src/main/res/layout/fragment_profile_timeline.xml @@ -1,4 +1,5 @@ - - \ No newline at end of file + + + \ No newline at end of file diff --git a/app/MyHyvesBookPlusStagram/app/src/main/res/layout/fragment_timeline.xml b/app/MyHyvesBookPlusStagram/app/src/main/res/layout/fragment_timeline.xml index fe7a080..effb17f 100644 --- a/app/MyHyvesBookPlusStagram/app/src/main/res/layout/fragment_timeline.xml +++ b/app/MyHyvesBookPlusStagram/app/src/main/res/layout/fragment_timeline.xml @@ -1,4 +1,5 @@ - + - \ No newline at end of file + \ No newline at end of file -- 2.49.1 From 6258c2a91af0c76a0c3a01730adcdd7f26621fbc Mon Sep 17 00:00:00 2001 From: Niels Zwemmer Date: Thu, 29 Jun 2017 15:20:40 +0200 Subject: [PATCH 12/22] Fixed the refresh combined with the progressBar. --- .../java/nl/myhyvesbookplus/tagram/TimelineFragment.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/TimelineFragment.java b/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/TimelineFragment.java index b4d56d8..8259b44 100644 --- a/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/TimelineFragment.java +++ b/app/MyHyvesBookPlusStagram/app/src/main/java/nl/myhyvesbookplus/tagram/TimelineFragment.java @@ -1,6 +1,7 @@ package nl.myhyvesbookplus.tagram; import android.app.Fragment; +import android.app.ProgressDialog; import android.os.Bundle; import android.os.Handler; import android.support.v4.widget.SwipeRefreshLayout; @@ -26,11 +27,13 @@ public class TimelineFragment extends Fragment { public TimelineFragment() {} /** + * Overridden onCreate which also starts a progress dialog for the posts being downloaded. * @param savedInstanceState The standard return of the onCreate method. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); +// progressDialog = ProgressDialog.show(getActivity(), getString(R.string.please_wait), getString(R.string.downloading_posts), false, false); } /** @@ -48,12 +51,12 @@ public class TimelineFragment extends Fragment { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View timeLineInflater = inflater.inflate(R.layout.fragment_timeline, container, false); - progressBar = (ProgressBar) timeLineInflater.findViewById(R.id.progressbar_timeline); - progressBar.setVisibility(View.VISIBLE); - listView = (ListView) timeLineInflater.findViewById(R.id.list); final SwipeRefreshLayout swipeView = (SwipeRefreshLayout) timeLineInflater.findViewById(R.id.swipe); + progressBar = (ProgressBar) timeLineInflater.findViewById(R.id.progressbar_timeline); + progressBar.setVisibility(View.VISIBLE); + swipeView.setEnabled(false); downloadClass = new DownloadClass(getActivity()); downloadClass.getPostsFromServer(); -- 2.49.1 From 5a6abe85f16ce63e8e43acaeaa313fe0569c9076 Mon Sep 17 00:00:00 2001 From: Felix Atsma Date: Thu, 29 Jun 2017 15:41:16 +0200 Subject: [PATCH 13/22] Timeline layout now with imagebutton --- .../app/src/main/res/drawable/niet_slecht.png | Bin 0 -> 45314 bytes .../main/res/layout/list_item_timeline.xml | 32 ++++++++++-------- 2 files changed, 18 insertions(+), 14 deletions(-) create mode 100644 app/MyHyvesBookPlusStagram/app/src/main/res/drawable/niet_slecht.png diff --git a/app/MyHyvesBookPlusStagram/app/src/main/res/drawable/niet_slecht.png b/app/MyHyvesBookPlusStagram/app/src/main/res/drawable/niet_slecht.png new file mode 100644 index 0000000000000000000000000000000000000000..73d711774978e9ffb1eb172438bbb9aabd74385e GIT binary patch literal 45314 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

NvUaa=3t1HA`b|AHI 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 EKMGE8E&u=k literal 0 HcmV?d00001 diff --git a/app/MyHyvesBookPlusStagram/app/src/main/res/layout/list_item_timeline.xml b/app/MyHyvesBookPlusStagram/app/src/main/res/layout/list_item_timeline.xml index e4d92b8..dfacaab 100644 --- a/app/MyHyvesBookPlusStagram/app/src/main/res/layout/list_item_timeline.xml +++ b/app/MyHyvesBookPlusStagram/app/src/main/res/layout/list_item_timeline.xml @@ -21,39 +21,43 @@ android:layout_gravity="center" android:layout_height="250dp" /> + + + android:text="Hallo Ik ben een comment!" /> -