From 2f2d56e6a0c1355f726c8d435053382718eed103 Mon Sep 17 00:00:00 2001 From: Zakjo Date: Sun, 28 Feb 2021 05:33:39 +0200 Subject: [PATCH 1/8] Adding Upcoming Events Feature --- .idea/compiler.xml | 2 +- .idea/misc.xml | 2 +- .../houseclub/api/methods/GetEvents.java | 16 ++ .../houseclub/api/methods/SearchPeople.java | 26 ++ .../me/grishka/houseclub/api/model/Event.java | 1 - .../houseclub/fragments/EventsFragment.java | 226 ++++++++++++++++++ .../houseclub/fragments/HomeFragment.java | 37 ++- .../fragments/SearchListFragment.java | 103 ++++++++ .../ic_baseline_calendar_today_24.xml | 10 + .../drawable/ic_baseline_mail_outline_24.xml | 10 + .../res/drawable/ic_baseline_people_24.xml | 10 + .../res/drawable/ic_baseline_search_24.xml | 10 + Houseclub/src/main/res/layout/event_row.xml | 71 ++++++ .../src/main/res/layout/search_panel.xml | 19 ++ Houseclub/src/main/res/menu/menu_home.xml | 38 +++ Houseclub/src/main/res/values/strings.xml | 2 + 16 files changed, 572 insertions(+), 11 deletions(-) create mode 100644 Houseclub/src/main/java/me/grishka/houseclub/api/methods/GetEvents.java create mode 100644 Houseclub/src/main/java/me/grishka/houseclub/api/methods/SearchPeople.java create mode 100644 Houseclub/src/main/java/me/grishka/houseclub/fragments/EventsFragment.java create mode 100644 Houseclub/src/main/java/me/grishka/houseclub/fragments/SearchListFragment.java create mode 100644 Houseclub/src/main/res/drawable/ic_baseline_calendar_today_24.xml create mode 100644 Houseclub/src/main/res/drawable/ic_baseline_mail_outline_24.xml create mode 100644 Houseclub/src/main/res/drawable/ic_baseline_people_24.xml create mode 100644 Houseclub/src/main/res/drawable/ic_baseline_search_24.xml create mode 100644 Houseclub/src/main/res/layout/event_row.xml create mode 100644 Houseclub/src/main/res/layout/search_panel.xml create mode 100644 Houseclub/src/main/res/menu/menu_home.xml diff --git a/.idea/compiler.xml b/.idea/compiler.xml index 7e7ee626..61a9130c 100644 --- a/.idea/compiler.xml +++ b/.idea/compiler.xml @@ -1,6 +1,6 @@ - + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml index c4e42dc4..794aa67e 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,4 +1,4 @@ - + \ No newline at end of file diff --git a/Houseclub/src/main/java/me/grishka/houseclub/api/methods/GetEvents.java b/Houseclub/src/main/java/me/grishka/houseclub/api/methods/GetEvents.java new file mode 100644 index 00000000..354bc50f --- /dev/null +++ b/Houseclub/src/main/java/me/grishka/houseclub/api/methods/GetEvents.java @@ -0,0 +1,16 @@ +package me.grishka.houseclub.api.methods; + +import java.util.List; + +import me.grishka.houseclub.api.ClubhouseAPIRequest; +import me.grishka.houseclub.api.model.Event; + +public class GetEvents extends ClubhouseAPIRequest { + public GetEvents(){ + super("GET", "get_events", Response.class); + } + + public static class Response{ + public List events; + } +} diff --git a/Houseclub/src/main/java/me/grishka/houseclub/api/methods/SearchPeople.java b/Houseclub/src/main/java/me/grishka/houseclub/api/methods/SearchPeople.java new file mode 100644 index 00000000..b516eddc --- /dev/null +++ b/Houseclub/src/main/java/me/grishka/houseclub/api/methods/SearchPeople.java @@ -0,0 +1,26 @@ +package me.grishka.houseclub.api.methods; + +import java.util.List; + +import me.grishka.houseclub.api.ClubhouseAPIRequest; +import me.grishka.houseclub.api.model.FullUser; + +public class SearchPeople extends ClubhouseAPIRequest { + public SearchPeople(String query) { + super("POST", "search_users", Resp.class); + requestBody = new Body(query); + } + + private static class Body { + public String query; + + public Body(String query) { + this.query = query; + } + } + + public static class Resp { + public List users; + public int count; + } +} diff --git a/Houseclub/src/main/java/me/grishka/houseclub/api/model/Event.java b/Houseclub/src/main/java/me/grishka/houseclub/api/model/Event.java index ea1ae9b8..51cbb2de 100644 --- a/Houseclub/src/main/java/me/grishka/houseclub/api/model/Event.java +++ b/Houseclub/src/main/java/me/grishka/houseclub/api/model/Event.java @@ -11,5 +11,4 @@ public class Event{ public int eventId; public boolean isMemberOnly; public List hosts; - public boolean clubIsMember, clubIsFollower; } diff --git a/Houseclub/src/main/java/me/grishka/houseclub/fragments/EventsFragment.java b/Houseclub/src/main/java/me/grishka/houseclub/fragments/EventsFragment.java new file mode 100644 index 00000000..61900994 --- /dev/null +++ b/Houseclub/src/main/java/me/grishka/houseclub/fragments/EventsFragment.java @@ -0,0 +1,226 @@ +package me.grishka.houseclub.fragments; + +import android.app.Activity; +import android.content.res.Configuration; +import android.graphics.Bitmap; +import android.graphics.Outline; +import android.graphics.Rect; +import android.graphics.drawable.ColorDrawable; +import android.graphics.drawable.Drawable; +import android.os.Bundle; +import android.view.View; +import android.view.ViewGroup; +import android.view.ViewOutlineProvider; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.stream.Collectors; + +import me.grishka.appkit.api.SimpleCallback; +import me.grishka.appkit.fragments.BaseRecyclerFragment; +import me.grishka.appkit.imageloader.ImageLoaderRecyclerAdapter; +import me.grishka.appkit.imageloader.ImageLoaderViewHolder; +import me.grishka.appkit.utils.BindableViewHolder; +import me.grishka.appkit.utils.V; +import me.grishka.houseclub.R; +import me.grishka.houseclub.api.methods.GetEvents; +import me.grishka.houseclub.api.model.Event; + +public class EventsFragment extends BaseRecyclerFragment{ + + private EventsAdapter adapter; + private ViewOutlineProvider roundedCornersOutline =new ViewOutlineProvider(){ + @Override + public void getOutline(View view, Outline outline){ + outline.setRoundRect(0, 0, view.getWidth(), view.getHeight(), V.dp(8)); + } + }; + + public EventsFragment(){ + super(20); + } + + @Override + public void onAttach(Activity activity){ + super.onAttach(activity); + setTitle(R.string.event_title); + loadData(); + setHasOptionsMenu(true); + } + + @Override + protected void doLoadData(int offset, int count){ + currentRequest=new GetEvents() + .setCallback(new SimpleCallback(this){ + @Override + public void onSuccess(GetEvents.Response result){ + currentRequest=null; + onDataLoaded(result.events, false); + } + }).exec(); + } + + @Override + public void onViewCreated(View view, Bundle savedInstanceState){ + super.onViewCreated(view, savedInstanceState); + list.addItemDecoration(new RecyclerView.ItemDecoration(){ + @Override + public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state){ + outRect.bottom=outRect.top=V.dp(8); + outRect.left=outRect.right=V.dp(16); + } + }); + getToolbar().setElevation(0); + } + + @Override + public void onConfigurationChanged(Configuration newConfig){ + super.onConfigurationChanged(newConfig); + getToolbar().setElevation(0); + } + + @Override + protected RecyclerView.Adapter getAdapter(){ + if(adapter==null){ + adapter=new EventsAdapter(); + adapter.setHasStableIds(true); + } + return adapter; + } + + @Override + public boolean wantsLightNavigationBar(){ + return true; + } + + @Override + public boolean wantsLightStatusBar(){ + return true; + } + + private class EventsAdapter extends RecyclerView.Adapter implements ImageLoaderRecyclerAdapter{ + + @NonNull + @Override + public EventViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType){ + return new EventViewHolder(); + } + + @Override + public void onBindViewHolder(@NonNull EventViewHolder holder, int position){ + holder.bind(data.get(position)); + } + + @Override + public int getItemCount(){ + return data.size(); + } + + @Override + public long getItemId(int position){ + return data.get(position).eventId; + } + + @Override + public int getImageCountForItem(int position){ + Event eve= data.get(position); + int count=0; + for(int i=0;i implements View.OnClickListener, ImageLoaderViewHolder{ + + private TextView start_at , topic, hosts,description; + private ImageView pic1, pic2; + private Drawable placeholder=new ColorDrawable(getResources().getColor(R.color.grey)); + + + public EventViewHolder() { + super(getActivity(), R.layout.event_row); + start_at=findViewById(R.id.event_start_time); + topic=findViewById(R.id.topic); + description=findViewById(R.id.description); + hosts=findViewById(R.id.hosts); + pic1=findViewById(R.id.pic1); + pic2=findViewById(R.id.pic2); + + itemView.setOutlineProvider(roundedCornersOutline); + itemView.setClipToOutline(true); + itemView.setElevation(V.dp(2)); + itemView.setOnClickListener(this); + + } + + + + @Override + public void onBind(Event item){ + + DateFormat dateFormat = new SimpleDateFormat("dd MMMM yyyy hh:mm"); + String strDate = dateFormat.format(item.timeStart); + start_at.setText(strDate); + + topic.setText(item.name); + + description.setText(item.description); + + hosts.setText( + + item.hosts.stream() + .map(hosts-> hosts.name) + .collect(Collectors.joining("\n")) + ); + + imgLoader.bindViewHolder(adapter, this, getAdapterPosition()); + } + + @Override + public void onClick(View view) { + + } + + private ImageView imgForIndex(int index){ + if(index==0) + return pic1; + return pic2; + } + + @Override + public void setImage(int index, Bitmap bitmap) { + if(index==0 && item.hosts.get(0).photoUrl==null) + index=1; + imgForIndex(index).setImageBitmap(bitmap); + } + + @Override + public void clearImage(int index){ + imgForIndex(index).setImageDrawable(placeholder); + } + + + } +} diff --git a/Houseclub/src/main/java/me/grishka/houseclub/fragments/HomeFragment.java b/Houseclub/src/main/java/me/grishka/houseclub/fragments/HomeFragment.java index c901025b..6736d769 100644 --- a/Houseclub/src/main/java/me/grishka/houseclub/fragments/HomeFragment.java +++ b/Houseclub/src/main/java/me/grishka/houseclub/fragments/HomeFragment.java @@ -113,20 +113,41 @@ public boolean wantsLightStatusBar(){ @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater){ - menu.add(0,0,0,"").setIcon(R.drawable.ic_notifications).setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS); - menu.add(0,1,0,"").setIcon(R.drawable.ic_baseline_person_24).setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS); +// menu.add(0,0,0,"").setIcon(R.drawable.ic_notifications).setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS); +// menu.add(0,1,0,"").setIcon(R.drawable.ic_baseline_person_24).setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS); + + inflater.inflate(R.menu.menu_home, menu); + + } @Override public boolean onOptionsItemSelected(MenuItem item){ - Bundle args=new Bundle(); - args.putInt("id", Integer.parseInt(ClubhouseSession.userID)); - if(item.getItemId()==0) { - Nav.go(getActivity(), NotificationListFragment.class, args); - } else if(item.getItemId()==1){ + if (item.getItemId() == R.id.homeMenuProfile) { + Bundle args=new Bundle(); + args.putInt("id", Integer.parseInt(ClubhouseSession.userID)); Nav.go(getActivity(), ProfileFragment.class, args); + return true; } - return true; + else if (item.getItemId() == R.id.homeMenuSearchPeople) { + Bundle args = new Bundle(); + Nav.go(getActivity(), SearchListFragment.class, args); + return true; + } + else if (item.getItemId() == R.id.homeMenuNotifications) { + Bundle args = new Bundle(); + args.putInt("id", Integer.parseInt(ClubhouseSession.userID)); + Nav.go(getActivity(), NotificationListFragment.class, args); + return true; + } + else if (item.getItemId() == R.id.homeMenuEvents) { + Bundle args = new Bundle(); + args.putInt("id", Integer.parseInt(ClubhouseSession.userID)); + Nav.go(getActivity(), EventsFragment.class, args); + return true; + } + return super.onOptionsItemSelected(item); + } private class ChannelAdapter extends RecyclerView.Adapter implements ImageLoaderRecyclerAdapter{ diff --git a/Houseclub/src/main/java/me/grishka/houseclub/fragments/SearchListFragment.java b/Houseclub/src/main/java/me/grishka/houseclub/fragments/SearchListFragment.java new file mode 100644 index 00000000..22bd561e --- /dev/null +++ b/Houseclub/src/main/java/me/grishka/houseclub/fragments/SearchListFragment.java @@ -0,0 +1,103 @@ +package me.grishka.houseclub.fragments; + +import android.app.Activity; +import android.os.Bundle; +import android.view.View; +import android.widget.SearchView; + +import me.grishka.appkit.api.SimpleCallback; +import me.grishka.houseclub.R; +import me.grishka.houseclub.api.methods.SearchPeople; + +public class SearchListFragment extends UserListFragment { + + private SearchView searchView; + private SearchView.OnQueryTextListener onQueryTextListener; + + protected static int min_query_lenght = 2; + protected String searchQuery; + private static final long DELAY = 200; + private long timestamp = System.currentTimeMillis(); + + @Override + public void onAttach(Activity activity){ + super.onAttach(activity); + setTitle(R.string.search_people_hint); + } + + @Override + public void onViewCreated(View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + + View search_panel = view.inflate(getContext(), R.layout.search_panel, null); + + searchView = search_panel.findViewById(R.id.searchView); + searchView.setQueryHint(getString(R.string.search_people_hint)); + onQueryTextListener = new OnSearchQueryTextListener(); + + getToolbar().addView(search_panel); + } + + protected void onQueryChanged(String query) { + long currentTimeStamp = System.currentTimeMillis(); + if (currentTimeStamp - timestamp < DELAY) { + timestamp = currentTimeStamp; + return; + } + + if (query == null && min_query_lenght > 0 || query.length() <= min_query_lenght) { + timestamp = currentTimeStamp; + return; + } + timestamp = currentTimeStamp; + searchQuery = query; + loadData(); + } + + private class OnSearchQueryTextListener implements SearchView.OnQueryTextListener { + @Override + public boolean onQueryTextSubmit(String query) { + onQueryChanged(query); + return false; + } + + @Override + public boolean onQueryTextChange(String newText) { + onQueryChanged(newText); + return false; + } + } + + @Override + public void onResume() { + super.onResume(); + searchView.setOnQueryTextListener(onQueryTextListener); + } + + @Override + public void onPause() { + super.onPause(); + searchView.setOnQueryTextListener(null); + } + + @Override + protected void doLoadData(int offset, int count) { + if (currentRequest != null) { + currentRequest.cancel(); + } + + currentRequest = new SearchPeople(searchQuery) + .setCallback(new SimpleCallback(this) { + @Override + public void onSuccess(SearchPeople.Resp result) { + currentRequest=null; + data.clear(); + onDataLoaded(result.users, false); + } + }).exec(); + } + + + + +} diff --git a/Houseclub/src/main/res/drawable/ic_baseline_calendar_today_24.xml b/Houseclub/src/main/res/drawable/ic_baseline_calendar_today_24.xml new file mode 100644 index 00000000..8f05bd34 --- /dev/null +++ b/Houseclub/src/main/res/drawable/ic_baseline_calendar_today_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/Houseclub/src/main/res/drawable/ic_baseline_mail_outline_24.xml b/Houseclub/src/main/res/drawable/ic_baseline_mail_outline_24.xml new file mode 100644 index 00000000..9a40c829 --- /dev/null +++ b/Houseclub/src/main/res/drawable/ic_baseline_mail_outline_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/Houseclub/src/main/res/drawable/ic_baseline_people_24.xml b/Houseclub/src/main/res/drawable/ic_baseline_people_24.xml new file mode 100644 index 00000000..88a083ad --- /dev/null +++ b/Houseclub/src/main/res/drawable/ic_baseline_people_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/Houseclub/src/main/res/drawable/ic_baseline_search_24.xml b/Houseclub/src/main/res/drawable/ic_baseline_search_24.xml new file mode 100644 index 00000000..84683b00 --- /dev/null +++ b/Houseclub/src/main/res/drawable/ic_baseline_search_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/Houseclub/src/main/res/layout/event_row.xml b/Houseclub/src/main/res/layout/event_row.xml new file mode 100644 index 00000000..7ff72ca3 --- /dev/null +++ b/Houseclub/src/main/res/layout/event_row.xml @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Houseclub/src/main/res/layout/search_panel.xml b/Houseclub/src/main/res/layout/search_panel.xml new file mode 100644 index 00000000..6a053dcf --- /dev/null +++ b/Houseclub/src/main/res/layout/search_panel.xml @@ -0,0 +1,19 @@ + + + + + + + \ No newline at end of file diff --git a/Houseclub/src/main/res/menu/menu_home.xml b/Houseclub/src/main/res/menu/menu_home.xml new file mode 100644 index 00000000..ad36f600 --- /dev/null +++ b/Houseclub/src/main/res/menu/menu_home.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Houseclub/src/main/res/values/strings.xml b/Houseclub/src/main/res/values/strings.xml index 26398c3c..53a73a03 100644 --- a/Houseclub/src/main/res/values/strings.xml +++ b/Houseclub/src/main/res/values/strings.xml @@ -51,6 +51,8 @@ Following Followers Following + Upcoming Events + Search People Notifications Unfollow %s? Yes From 73294c4263415a3f895ed01f035d9ae2ee93f16c Mon Sep 17 00:00:00 2001 From: Zakjo Date: Sun, 28 Feb 2021 09:49:17 +0200 Subject: [PATCH 2/8] Added "Followed by" to users profile --- .idea/misc.xml | 2 +- .../grishka/houseclub/api/model/FullUser.java | 3 + .../houseclub/fragments/HomeFragment.java | 3 +- .../houseclub/fragments/ProfileFragment.java | 92 ++++++++++++++++++- Houseclub/src/main/res/layout/profile.xml | 75 ++++++++++++++- 5 files changed, 170 insertions(+), 5 deletions(-) diff --git a/.idea/misc.xml b/.idea/misc.xml index 794aa67e..58918f50 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,4 +1,4 @@ - + \ No newline at end of file diff --git a/Houseclub/src/main/java/me/grishka/houseclub/api/model/FullUser.java b/Houseclub/src/main/java/me/grishka/houseclub/api/model/FullUser.java index 2eef2405..2132dc13 100644 --- a/Houseclub/src/main/java/me/grishka/houseclub/api/model/FullUser.java +++ b/Houseclub/src/main/java/me/grishka/houseclub/api/model/FullUser.java @@ -1,6 +1,7 @@ package me.grishka.houseclub.api.model; import java.util.Date; +import java.util.List; public class FullUser extends User{ public String dsplayname, bio, twitter, instagram; @@ -8,6 +9,8 @@ public class FullUser extends User{ public boolean followsMe, isBlockedByNetwork; public Date timeCreated; public User invitedByUserProfile; + public List mutualFollows; + // null = not following // 2 = following // other values = ? diff --git a/Houseclub/src/main/java/me/grishka/houseclub/fragments/HomeFragment.java b/Houseclub/src/main/java/me/grishka/houseclub/fragments/HomeFragment.java index 6736d769..5afea30f 100644 --- a/Houseclub/src/main/java/me/grishka/houseclub/fragments/HomeFragment.java +++ b/Houseclub/src/main/java/me/grishka/houseclub/fragments/HomeFragment.java @@ -225,7 +225,8 @@ public void onBind(Channel item){ topic.setText(item.topic); numMembers.setText(""+item.numAll); numSpeakers.setText(""+item.numSpeakers); - speakers.setText(item.users.stream().map(user->user.isSpeaker ? (user.name+" 💬") : user.name).collect(Collectors.joining("\n"))); + speakers.setText(item.users.stream().map(user->user.isSpeaker ? (user.name+" 💬") : user.name) + .collect(Collectors.joining("\n")) ); imgLoader.bindViewHolder(adapter, this, getAdapterPosition()); } diff --git a/Houseclub/src/main/java/me/grishka/houseclub/fragments/ProfileFragment.java b/Houseclub/src/main/java/me/grishka/houseclub/fragments/ProfileFragment.java index e0ee265a..4495cb9b 100644 --- a/Houseclub/src/main/java/me/grishka/houseclub/fragments/ProfileFragment.java +++ b/Houseclub/src/main/java/me/grishka/houseclub/fragments/ProfileFragment.java @@ -6,6 +6,7 @@ import android.content.Intent; import android.content.res.Configuration; import android.graphics.Bitmap; +import android.graphics.BitmapFactory; import android.graphics.drawable.ColorDrawable; import android.net.Uri; import android.os.Bundle; @@ -24,7 +25,11 @@ import android.widget.TextView; import android.widget.Toast; +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; import java.text.DateFormat; +import java.util.stream.Collectors; import me.grishka.appkit.Nav; import me.grishka.appkit.api.Callback; @@ -53,8 +58,8 @@ public class ProfileFragment extends LoaderFragment{ private FullUser user; private TextView name, username, followers, following, followsYou, bio, inviteInfo, twitter, instagram, - invites; - private ImageView photo, inviterPhoto; + invites , mutuals , followed_by; + private ImageView photo, inviterPhoto , pic1 , pic2 , pic3 ; private Button followBtn, inviteButton; private EditText invitePhoneNum; private View socialButtons, inviteLayout; @@ -82,6 +87,10 @@ public View onCreateContentView(LayoutInflater inflater, ViewGroup container, Bu inviteInfo=v.findViewById(R.id.invite_info); photo=v.findViewById(R.id.photo); inviterPhoto=v.findViewById(R.id.inviter_photo); + pic1=v.findViewById(R.id.pic1); + pic2=v.findViewById(R.id.pic2); + pic3=v.findViewById(R.id.pic3); + followBtn=v.findViewById(R.id.follow_btn); twitter=v.findViewById(R.id.twitter); instagram=v.findViewById(R.id.instagram); @@ -89,6 +98,8 @@ public View onCreateContentView(LayoutInflater inflater, ViewGroup container, Bu inviteLayout = v.findViewById(R.id.invite_layout); inviteButton = v.findViewById(R.id.invite_button); invites = v.findViewById(R.id.num_of_invites); + mutuals = v.findViewById(R.id.mutuals); + followed_by = v.findViewById(R.id.followed_by); invitePhoneNum = v.findViewById(R.id.invite_phone_num); followBtn.setOnClickListener(this::onFollowClick); @@ -160,15 +171,92 @@ public void onSuccess(GetProfile.Response result){ }else{ inviterPhoto.setVisibility(View.GONE); } + + if(user.mutualFollows.size() > 0){ + + followed_by.setText(" Followed by "); + + String usernames = ""; + for(int i = 0 ; i< user.mutualFollows.size(); i++){ + + if(i>0){ + usernames += ", "+user.mutualFollows.get(i).username; + }else{ + usernames += user.mutualFollows.get(i).username; + + } + + if(i == 0){ + if(user.mutualFollows.get(i).photoUrl != null){ + ColorDrawable d2=new ColorDrawable(getResources().getColor(R.color.grey)); + if(user.mutualFollows.get(i).photoUrl!=null) { + pic1.setVisibility(View.VISIBLE); + ViewImageLoader.load(pic1, d2, user.mutualFollows.get(i).photoUrl); + }else{ + pic1.setImageDrawable(d2); + } + }else{ + pic1.setVisibility(View.GONE); + } + } + + if(i == 1){ + if(user.mutualFollows.get(i).photoUrl !=null){ + ColorDrawable d2=new ColorDrawable(getResources().getColor(R.color.grey)); + if(user.mutualFollows.get(i).photoUrl!=null) { + pic2.setVisibility(View.VISIBLE); + ViewImageLoader.load(pic2, d2, user.mutualFollows.get(i).photoUrl); + }else{ + pic2.setImageDrawable(d2); + } + }else{ + pic2.setVisibility(View.GONE); + } + } + + if(i == 2){ + + if(user.mutualFollows.size() > 3){ + usernames += "and " + String.valueOf(user.mutualFollows.size() - 3) + "others"; + } + + if( user.mutualFollows.get(i).photoUrl !=null){ + ColorDrawable d2=new ColorDrawable(getResources().getColor(R.color.grey)); + if(user.mutualFollows.get(i).photoUrl!=null) { + pic3.setVisibility(View.VISIBLE); + ViewImageLoader.load(pic3, d2, user.mutualFollows.get(i).photoUrl); + }else{ + pic3.setImageDrawable(d2); + } + }else{ + pic3.setVisibility(View.GONE); + } + + } + + } + + mutuals.setText(usernames); + + } + inviteInfo.setText(joined); + + + + + dataLoaded(); + } }) .exec(); loadInvites(); } + + @Override public void onRefresh(){ loadData(); diff --git a/Houseclub/src/main/res/layout/profile.xml b/Houseclub/src/main/res/layout/profile.xml index ed9ae7a8..92a414a4 100644 --- a/Houseclub/src/main/res/layout/profile.xml +++ b/Houseclub/src/main/res/layout/profile.xml @@ -91,11 +91,12 @@ + @@ -131,10 +132,80 @@ android:drawablePadding="8dp" tools:text="instagram"/> + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -188,6 +259,8 @@ + + \ No newline at end of file From a743e2419fb51556f62b6b020109e8799870ff3c Mon Sep 17 00:00:00 2001 From: Zakjo Date: Sun, 28 Feb 2021 09:51:32 +0200 Subject: [PATCH 3/8] Added "Followed by" to users profile --- .../main/java/me/grishka/houseclub/fragments/HomeFragment.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Houseclub/src/main/java/me/grishka/houseclub/fragments/HomeFragment.java b/Houseclub/src/main/java/me/grishka/houseclub/fragments/HomeFragment.java index 5afea30f..525c9360 100644 --- a/Houseclub/src/main/java/me/grishka/houseclub/fragments/HomeFragment.java +++ b/Houseclub/src/main/java/me/grishka/houseclub/fragments/HomeFragment.java @@ -225,8 +225,7 @@ public void onBind(Channel item){ topic.setText(item.topic); numMembers.setText(""+item.numAll); numSpeakers.setText(""+item.numSpeakers); - speakers.setText(item.users.stream().map(user->user.isSpeaker ? (user.name+" 💬") : user.name) - .collect(Collectors.joining("\n")) ); + speakers.setText(item.users.stream().map(user->user.isSpeaker ? (user.name+" 💬") : user.name).collect(Collectors.joining("\n")) ); imgLoader.bindViewHolder(adapter, this, getAdapterPosition()); } From bbc07762ce004ec4623e8bd4c0c9568d6bc80174 Mon Sep 17 00:00:00 2001 From: Zakjo Date: Mon, 1 Mar 2021 19:33:30 +0200 Subject: [PATCH 4/8] add insta --- Houseclub/build.gradle | 7 ++ .../houseclub/api/ClubhouseAPIController.java | 15 ++- .../houseclub/api/methods/AudienceReply.java | 2 + .../api/methods/UpdateInstagram.java | 19 +++ .../houseclub/fragments/HomeFragment.java | 1 + .../fragments/InChannelFragment.java | 5 +- .../fragments/NotificationListFragment.java | 2 +- .../houseclub/fragments/ProfileFragment.java | 114 +++++++++++++++++- Houseclub/src/main/res/layout/profile.xml | 10 +- Houseclub/src/main/res/values/strings.xml | 5 + gradle.properties | 2 + 11 files changed, 168 insertions(+), 14 deletions(-) create mode 100644 Houseclub/src/main/java/me/grishka/houseclub/api/methods/UpdateInstagram.java diff --git a/Houseclub/build.gradle b/Houseclub/build.gradle index 3b477dcb..1febac31 100644 --- a/Houseclub/build.gradle +++ b/Houseclub/build.gradle @@ -9,6 +9,13 @@ android { targetSdkVersion 30 versionCode 9 versionName "1.0.8" + + Properties properties = new Properties() + if (project.rootProject.file('local.properties').canRead()) { + properties.load(project.rootProject.file("local.properties").newDataInputStream()) + } + + buildConfigField "String", "INSTAGRAM_APP_ID", '"'+properties.getProperty("instagramAppId")+'"' } buildTypes { release { diff --git a/Houseclub/src/main/java/me/grishka/houseclub/api/ClubhouseAPIController.java b/Houseclub/src/main/java/me/grishka/houseclub/api/ClubhouseAPIController.java index 68a9ac36..e622c0c4 100644 --- a/Houseclub/src/main/java/me/grishka/houseclub/api/ClubhouseAPIController.java +++ b/Houseclub/src/main/java/me/grishka/houseclub/api/ClubhouseAPIController.java @@ -31,9 +31,9 @@ public class ClubhouseAPIController{ private static final Uri API_URL=Uri.parse("https://www.clubhouseapi.com/api"); // private static final Uri API_URL=Uri.parse("http://192.168.0.51:8080/"); - private static final String API_BUILD_ID="304"; - private static final String API_BUILD_VERSION="0.1.28"; - private static final String API_UA="clubhouse/"+API_BUILD_ID+" (iPhone; iOS 13.5.1; Scale/3.00)"; + public static final String API_BUILD_ID="304"; + public static final String API_BUILD_VERSION="0.1.28"; + public static final String API_UA="clubhouse/"+API_BUILD_ID+" (iPhone; iOS 13.5.1; Scale/3.00)"; public static final String PUBNUB_PUB_KEY = "pub-c-6878d382-5ae6-4494-9099-f930f938868b"; public static final String PUBNUB_SUB_KEY = "sub-c-a4abea84-9ca3-11ea-8e71-f2b83ac9263d"; @@ -41,6 +41,9 @@ public class ClubhouseAPIController{ public static final String TWITTER_ID = "NyJhARWVYU1X3qJZtC2154xSI"; public static final String TWITTER_SECRET = "ylFImLBFaOE362uwr4jut8S8gXGWh93S1TUKbkfh7jDIPse02o"; + public static final String INSTAGRAM_ID = "1352866981588597"; + public static final String INSTAGRAM_CALLBACK = "https://www.joinclubhouse.com/callback/instagram"; + public static final String AGORA_KEY = "938de3e8055e42b281bb8c6f69c21f78"; public static final String SENTRY_KEY = "5374a416cd2d4009a781b49d1bd9ef44@o325556.ingest.sentry.io/5245095"; public static final String INSTABUG_KEY = "4e53155da9b00728caa5249f2e35d6b3"; @@ -150,6 +153,12 @@ public void run(){ if(DEBUG) Log.i(TAG, "Raw response: "+respStr); BaseResponse br=gson.fromJson(respStr, BaseResponse.class); + + String error; + if (!br.errorMessage.isEmpty()) error=br.errorMessage; + else error="ERROR with code " +resp.code(); + br.errorMessage = error; + req.onError(new ClubhouseErrorResponse(br)); } } diff --git a/Houseclub/src/main/java/me/grishka/houseclub/api/methods/AudienceReply.java b/Houseclub/src/main/java/me/grishka/houseclub/api/methods/AudienceReply.java index a7181252..dbd46b92 100644 --- a/Houseclub/src/main/java/me/grishka/houseclub/api/methods/AudienceReply.java +++ b/Houseclub/src/main/java/me/grishka/houseclub/api/methods/AudienceReply.java @@ -4,6 +4,7 @@ import me.grishka.houseclub.api.ClubhouseAPIRequest; public class AudienceReply extends ClubhouseAPIRequest{ + public AudienceReply(String channel, boolean raise){ super("POST", "audience_reply", BaseResponse.class); requestBody=new Body(channel, raise, !raise); @@ -19,4 +20,5 @@ public Body(String channel, boolean raiseHands, boolean unraiseHands){ this.unraiseHands=unraiseHands; } } + } diff --git a/Houseclub/src/main/java/me/grishka/houseclub/api/methods/UpdateInstagram.java b/Houseclub/src/main/java/me/grishka/houseclub/api/methods/UpdateInstagram.java new file mode 100644 index 00000000..07d805d0 --- /dev/null +++ b/Houseclub/src/main/java/me/grishka/houseclub/api/methods/UpdateInstagram.java @@ -0,0 +1,19 @@ +package me.grishka.houseclub.api.methods; + +import me.grishka.houseclub.api.BaseResponse; +import me.grishka.houseclub.api.ClubhouseAPIRequest; + +public class UpdateInstagram extends ClubhouseAPIRequest{ + public static String REDIRECT_INSTAGRAM_URL = "https://www.joinclubhouse.com/callback/instagram"; + public UpdateInstagram(String code) { + super("POST", "update_instagram_username", BaseResponse.class); + requestBody = new Body(code); + } + + private static class Body{ + public String code; + Body(String code){ + this.code = code; + } + } +} diff --git a/Houseclub/src/main/java/me/grishka/houseclub/fragments/HomeFragment.java b/Houseclub/src/main/java/me/grishka/houseclub/fragments/HomeFragment.java index 525c9360..2aa0d382 100644 --- a/Houseclub/src/main/java/me/grishka/houseclub/fragments/HomeFragment.java +++ b/Houseclub/src/main/java/me/grishka/houseclub/fragments/HomeFragment.java @@ -119,6 +119,7 @@ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater){ inflater.inflate(R.menu.menu_home, menu); + } @Override diff --git a/Houseclub/src/main/java/me/grishka/houseclub/fragments/InChannelFragment.java b/Houseclub/src/main/java/me/grishka/houseclub/fragments/InChannelFragment.java index 11f96414..cce4e838 100644 --- a/Houseclub/src/main/java/me/grishka/houseclub/fragments/InChannelFragment.java +++ b/Houseclub/src/main/java/me/grishka/houseclub/fragments/InChannelFragment.java @@ -14,6 +14,7 @@ import android.widget.ImageButton; import android.widget.ImageView; import android.widget.TextView; +import android.widget.Toast; import java.util.ArrayList; import java.util.List; @@ -56,6 +57,8 @@ public class InChannelFragment extends BaseRecyclerFragment impleme public InChannelFragment(){ super(10); setListLayoutId(R.layout.in_channel); + + } @Override @@ -154,7 +157,7 @@ private void onLeaveClick(View v){ } private void onRaiseClick(View v){ - VoiceService svc=VoiceService.getInstance(); + VoiceService svc = VoiceService.getInstance(); if(svc.isHandRaised()) svc.unraiseHand(); else diff --git a/Houseclub/src/main/java/me/grishka/houseclub/fragments/NotificationListFragment.java b/Houseclub/src/main/java/me/grishka/houseclub/fragments/NotificationListFragment.java index 3bf7aa1c..c7fd3fe6 100644 --- a/Houseclub/src/main/java/me/grishka/houseclub/fragments/NotificationListFragment.java +++ b/Houseclub/src/main/java/me/grishka/houseclub/fragments/NotificationListFragment.java @@ -127,7 +127,7 @@ public NotificationViewHolder(){ @Override public void onBind(Notification item){ - itemView.setAlpha(item.inUnread?1F:0.5F); + itemView.setAlpha(item.inUnread?1F:0.7F); name.setText(item.userProfile.name); message.setText(item.message); time.setText(DateUtils.getRelativeTimeSpanString(item.timeCreated.getTime())); diff --git a/Houseclub/src/main/java/me/grishka/houseclub/fragments/ProfileFragment.java b/Houseclub/src/main/java/me/grishka/houseclub/fragments/ProfileFragment.java index 4495cb9b..4768210b 100644 --- a/Houseclub/src/main/java/me/grishka/houseclub/fragments/ProfileFragment.java +++ b/Houseclub/src/main/java/me/grishka/houseclub/fragments/ProfileFragment.java @@ -19,6 +19,9 @@ import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; +import android.webkit.WebResourceRequest; +import android.webkit.WebView; +import android.webkit.WebViewClient; import android.widget.Button; import android.widget.EditText; import android.widget.ImageView; @@ -29,6 +32,7 @@ import java.net.MalformedURLException; import java.net.URL; import java.text.DateFormat; +import java.util.HashMap; import java.util.stream.Collectors; import me.grishka.appkit.Nav; @@ -37,9 +41,11 @@ import me.grishka.appkit.api.SimpleCallback; import me.grishka.appkit.fragments.LoaderFragment; import me.grishka.appkit.imageloader.ViewImageLoader; +import me.grishka.houseclub.BuildConfig; import me.grishka.houseclub.R; import me.grishka.houseclub.VoiceService; import me.grishka.houseclub.api.BaseResponse; +import me.grishka.houseclub.api.ClubhouseAPIController; import me.grishka.houseclub.api.ClubhouseSession; import me.grishka.houseclub.api.methods.Follow; import me.grishka.houseclub.api.methods.GetProfile; @@ -47,6 +53,7 @@ import me.grishka.houseclub.api.methods.Me; import me.grishka.houseclub.api.methods.Unfollow; import me.grishka.houseclub.api.methods.UpdateBio; +import me.grishka.houseclub.api.methods.UpdateInstagram; import me.grishka.houseclub.api.methods.UpdatePhoto; import me.grishka.houseclub.api.methods.UpdateName; import me.grishka.houseclub.api.model.FullUser; @@ -63,6 +70,8 @@ public class ProfileFragment extends LoaderFragment{ private Button followBtn, inviteButton; private EditText invitePhoneNum; private View socialButtons, inviteLayout; + private WebView webView; + private boolean self; @Override @@ -94,6 +103,8 @@ public View onCreateContentView(LayoutInflater inflater, ViewGroup container, Bu followBtn=v.findViewById(R.id.follow_btn); twitter=v.findViewById(R.id.twitter); instagram=v.findViewById(R.id.instagram); + webView = v.findViewById(R.id.webView); + socialButtons=v.findViewById(R.id.social); inviteLayout = v.findViewById(R.id.invite_layout); inviteButton = v.findViewById(R.id.invite_button); @@ -115,6 +126,11 @@ public View onCreateContentView(LayoutInflater inflater, ViewGroup container, Bu inviteButton.setOnClickListener(this::onInviteClick); } + + webView.setVisibility(View.GONE); + webView.getSettings().setJavaScriptEnabled(true); + webView.getSettings().setJavaScriptCanOpenWindowsAutomatically(true); + return v; } @@ -148,16 +164,18 @@ public void onSuccess(GetProfile.Response result){ else followBtn.setText(user.isFollowed() ? R.string.following : R.string.follow); - if(user.twitter==null && user.instagram==null){ + if(!self && user.twitter==null && user.instagram==null){ socialButtons.setVisibility(View.GONE); }else{ socialButtons.setVisibility(View.VISIBLE); twitter.setVisibility(user.twitter==null ? View.GONE : View.VISIBLE); - instagram.setVisibility(user.instagram==null ? View.GONE : View.VISIBLE); + instagram.setVisibility(user.instagram==null && !self ? View.GONE : View.VISIBLE); if(user.twitter!=null) twitter.setText(user.twitter); if(user.instagram!=null) instagram.setText(user.instagram); + if(self && user.instagram==null) + instagram.setText(R.string.add_instagram); } String joined=getString(R.string.joined_date, DateFormat.getDateInstance().format(user.timeCreated)); @@ -183,7 +201,6 @@ public void onSuccess(GetProfile.Response result){ usernames += ", "+user.mutualFollows.get(i).username; }else{ usernames += user.mutualFollows.get(i).username; - } if(i == 0){ @@ -256,7 +273,6 @@ public void onSuccess(GetProfile.Response result){ } - @Override public void onRefresh(){ loadData(); @@ -274,7 +290,6 @@ public void onConfigurationChanged(Configuration newConfig){ getToolbar().setElevation(0); } - @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater){ menu.add(R.string.log_out); @@ -376,9 +391,98 @@ public void onError(ErrorResponse error){ } private void onInstagramClick(View v){ + if (self){ + HashMap headers = new HashMap<>(); + headers.put("CH-AppBuild", ClubhouseAPIController.API_BUILD_ID); + headers.put("CH-AppVersion", ClubhouseAPIController.API_BUILD_VERSION); + headers.put("User-Agent", ClubhouseAPIController.API_UA); + + headers.put("CH-DeviceId", ClubhouseSession.deviceID); + headers.put("Authorization", "Token "+ClubhouseSession.userToken); + headers.put("CH-UserID", ClubhouseSession.userID); + + if (user.instagram == null) { + webView.setVisibility(View.VISIBLE); + webView.setWebViewClient(new WebViewClient() { + @Override + public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) { + Boolean redirect = checkRedirect(request.getUrl().toString()); + view.loadUrl(request.getUrl().toString()); + return redirect; + } + + public boolean shouldOverrideUrlLoading(WebView view, String url) { + Boolean redirect = checkRedirect(url); + view.loadUrl(url); + return redirect; + } + }); + webView.loadUrl( + "https://www.instagram.com/oauth/authorize?client_id=" + + "1352866981588597" + + "&redirect_uri=" + UpdateInstagram.REDIRECT_INSTAGRAM_URL + + "&scope=user_profile" + + "&response_type=code", + headers + ); + } else { + new AlertDialog.Builder(getActivity()) + .setMessage(getString(R.string.confirm_unlink_instagram_title)) + .setMessage(getString(R.string.confirm_unlink_instagram)) + .setPositiveButton(R.string.yes, new DialogInterface.OnClickListener(){ + @Override + public void onClick(DialogInterface dialogInterface, int i){ + new UpdateInstagram(null) + .wrapProgress(getActivity()) + .setCallback(new Callback(){ + @Override + public void onSuccess(BaseResponse result){ + instagram.setText(R.string.add_instagram); + webView.setVisibility(View.GONE); + } + + @Override + public void onError(ErrorResponse error){ + error.showToast(getActivity()); + } + }) + .exec(); + } + }) + .setNegativeButton(R.string.no, null) + .show(); + } + } else startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://instagram.com/"+user.instagram))); } + private Boolean checkRedirect(String url){ + if (url.startsWith(UpdateInstagram.REDIRECT_INSTAGRAM_URL)) { + + // last2 chars is #_ by docs https://developers.facebook.com/docs/instagram-basic-display-api/getting-started + String code = url.substring((UpdateInstagram.REDIRECT_INSTAGRAM_URL+ "?code=").length(), url.length()-2); + + new UpdateInstagram(code) + .wrapProgress(getActivity()) + .setCallback(new Callback(){ + @Override + public void onSuccess(BaseResponse result){ + instagram.setText(R.string.instagram_linked); + webView.setVisibility(View.GONE); + } + + @Override + public void onError(ErrorResponse error){ + error.showToast(getActivity()); + } + }) + .exec(); + return false; + } else { + return true; + } + } + private void onTwitterClick(View v){ startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://twitter.com/"+user.twitter))); } diff --git a/Houseclub/src/main/res/layout/profile.xml b/Houseclub/src/main/res/layout/profile.xml index 92a414a4..80bee0e9 100644 --- a/Houseclub/src/main/res/layout/profile.xml +++ b/Houseclub/src/main/res/layout/profile.xml @@ -197,12 +197,14 @@ tools:text="username "/> - - - - + + Wait list You\'re waiting for someone to invite you to Clubhouse. Your account is currently inactive. Log out + Ongoing call Leave room Join this room? @@ -63,6 +64,10 @@ Update name Save This event hasn\'t started yet + Link instagram + Unlink instagram? + Are you sure want to unlink instagram? It can be linked in future + Instagram linked, reopen page to see This event has already ended Please log in again to activate your account. OK diff --git a/gradle.properties b/gradle.properties index c73d2393..e0638f5f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -17,3 +17,5 @@ org.gradle.jvmargs=-Xmx1536m android.useAndroidX=true # Automatically convert third-party libraries to use AndroidX android.enableJetifier=true + +instagramAppId=1352866981588597 From 36626edfab8267493134dc2474ce62c84d5427a1 Mon Sep 17 00:00:00 2001 From: Zakjo Date: Fri, 5 Mar 2021 18:47:26 +0200 Subject: [PATCH 5/8] Search Clubs , Follow & Unfollow Clubs , view user's clubs & mutual followers fix ( followed by ) --- .../me/grishka/houseclub/MainActivity.java | 7 +- .../houseclub/api/methods/FollowClub.java | 19 ++ .../houseclub/api/methods/GetClub.java | 29 +++ .../houseclub/api/methods/GetProfile.java | 1 + .../houseclub/api/methods/SearchClubs.java | 25 +++ .../houseclub/api/methods/UnfollowClub.java | 19 ++ .../me/grishka/houseclub/api/model/Club.java | 80 ++++++++ .../grishka/houseclub/api/model/FullUser.java | 5 +- .../me/grishka/houseclub/api/model/Topic.java | 63 ++++++ .../houseclub/fragments/ClubFragment.java | 190 ++++++++++++++++++ .../houseclub/fragments/ClubListFragment.java | 148 ++++++++++++++ .../houseclub/fragments/EventsFragment.java | 44 ++++ .../houseclub/fragments/HomeFragment.java | 7 + .../houseclub/fragments/ProfileFragment.java | 27 ++- .../fragments/SearchClubsListFragment.java | 104 ++++++++++ .../drawable/ic_baseline_person_add_24.xml | 10 + .../drawable/ic_baseline_person_search_24.xml | 16 ++ Houseclub/src/main/res/layout/club.xml | 124 ++++++++++++ .../src/main/res/layout/club_list_row.xml | 68 +++++++ Houseclub/src/main/res/layout/profile.xml | 39 +++- Houseclub/src/main/res/menu/menu_home.xml | 10 +- Houseclub/src/main/res/values/strings.xml | 1 + 22 files changed, 1022 insertions(+), 14 deletions(-) create mode 100644 Houseclub/src/main/java/me/grishka/houseclub/api/methods/FollowClub.java create mode 100644 Houseclub/src/main/java/me/grishka/houseclub/api/methods/GetClub.java create mode 100644 Houseclub/src/main/java/me/grishka/houseclub/api/methods/SearchClubs.java create mode 100644 Houseclub/src/main/java/me/grishka/houseclub/api/methods/UnfollowClub.java create mode 100644 Houseclub/src/main/java/me/grishka/houseclub/api/model/Club.java create mode 100644 Houseclub/src/main/java/me/grishka/houseclub/api/model/Topic.java create mode 100644 Houseclub/src/main/java/me/grishka/houseclub/fragments/ClubFragment.java create mode 100644 Houseclub/src/main/java/me/grishka/houseclub/fragments/ClubListFragment.java create mode 100644 Houseclub/src/main/java/me/grishka/houseclub/fragments/SearchClubsListFragment.java create mode 100644 Houseclub/src/main/res/drawable/ic_baseline_person_add_24.xml create mode 100644 Houseclub/src/main/res/drawable/ic_baseline_person_search_24.xml create mode 100644 Houseclub/src/main/res/layout/club.xml create mode 100644 Houseclub/src/main/res/layout/club_list_row.xml diff --git a/Houseclub/src/main/java/me/grishka/houseclub/MainActivity.java b/Houseclub/src/main/java/me/grishka/houseclub/MainActivity.java index f54d8c1c..da6496d2 100644 --- a/Houseclub/src/main/java/me/grishka/houseclub/MainActivity.java +++ b/Houseclub/src/main/java/me/grishka/houseclub/MainActivity.java @@ -3,6 +3,7 @@ import android.Manifest; import android.app.Activity; import android.app.AlertDialog; +import android.app.Fragment; import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; @@ -24,9 +25,12 @@ import me.grishka.houseclub.api.ClubhouseSession; import me.grishka.houseclub.api.methods.CheckWaitlistStatus; import me.grishka.houseclub.api.methods.GetChannel; +import me.grishka.houseclub.api.methods.GetClub; import me.grishka.houseclub.api.methods.GetEvent; import me.grishka.houseclub.api.methods.JoinChannel; import me.grishka.houseclub.api.model.Channel; +import me.grishka.houseclub.api.model.Club; +import me.grishka.houseclub.fragments.ClubFragment; import me.grishka.houseclub.fragments.HomeFragment; import me.grishka.houseclub.fragments.InChannelFragment; import me.grishka.houseclub.fragments.LoginFragment; @@ -41,8 +45,8 @@ public class MainActivity extends FragmentStackActivity{ @Override protected void onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState); - SharedPreferences prefs=getPreferences(MODE_PRIVATE); + if(!prefs.getBoolean("warningShown", false)){ new AlertDialog.Builder(this) .setTitle(R.string.warning) @@ -94,6 +98,7 @@ public void onError(ErrorResponse error){ } }else{ showFragment(new LoginFragment()); + } } diff --git a/Houseclub/src/main/java/me/grishka/houseclub/api/methods/FollowClub.java b/Houseclub/src/main/java/me/grishka/houseclub/api/methods/FollowClub.java new file mode 100644 index 00000000..e1320c64 --- /dev/null +++ b/Houseclub/src/main/java/me/grishka/houseclub/api/methods/FollowClub.java @@ -0,0 +1,19 @@ +package me.grishka.houseclub.api.methods; + +import me.grishka.houseclub.api.BaseResponse; +import me.grishka.houseclub.api.ClubhouseAPIRequest; + +public class FollowClub extends ClubhouseAPIRequest{ + public FollowClub(int clubId){ + super("POST", "follow_club", BaseResponse.class); + requestBody=new Body(clubId); + } + + private static class Body{ + public int clubId, source=4; + + public Body(int clubId){ + this.clubId=clubId; + } + } +} diff --git a/Houseclub/src/main/java/me/grishka/houseclub/api/methods/GetClub.java b/Houseclub/src/main/java/me/grishka/houseclub/api/methods/GetClub.java new file mode 100644 index 00000000..6a886eae --- /dev/null +++ b/Houseclub/src/main/java/me/grishka/houseclub/api/methods/GetClub.java @@ -0,0 +1,29 @@ +package me.grishka.houseclub.api.methods; + +import java.util.List; + +import me.grishka.houseclub.api.ClubhouseAPIRequest; +import me.grishka.houseclub.api.model.Club; +import me.grishka.houseclub.api.model.Topic; + +public class GetClub extends ClubhouseAPIRequest{ + + public GetClub(int id){ + super("POST", "get_club", Response.class); + requestBody=new Body(id); + } + + private static class Body{ + public int club_id; + public Body(int club_id){ this.club_id=club_id; } + } + + public static class Response{ + public Club club; + public boolean is_admin; + public boolean is_member; + public boolean is_follower; + public List topics; + } + +} diff --git a/Houseclub/src/main/java/me/grishka/houseclub/api/methods/GetProfile.java b/Houseclub/src/main/java/me/grishka/houseclub/api/methods/GetProfile.java index af4d59e3..f999465b 100644 --- a/Houseclub/src/main/java/me/grishka/houseclub/api/methods/GetProfile.java +++ b/Houseclub/src/main/java/me/grishka/houseclub/api/methods/GetProfile.java @@ -1,6 +1,7 @@ package me.grishka.houseclub.api.methods; import me.grishka.houseclub.api.ClubhouseAPIRequest; +import me.grishka.houseclub.api.model.Club; import me.grishka.houseclub.api.model.FullUser; public class GetProfile extends ClubhouseAPIRequest{ diff --git a/Houseclub/src/main/java/me/grishka/houseclub/api/methods/SearchClubs.java b/Houseclub/src/main/java/me/grishka/houseclub/api/methods/SearchClubs.java new file mode 100644 index 00000000..fa037349 --- /dev/null +++ b/Houseclub/src/main/java/me/grishka/houseclub/api/methods/SearchClubs.java @@ -0,0 +1,25 @@ +package me.grishka.houseclub.api.methods; + +import java.util.List; + +import me.grishka.houseclub.api.ClubhouseAPIRequest; +import me.grishka.houseclub.api.model.Club; + +public class SearchClubs extends ClubhouseAPIRequest { + public SearchClubs(String query) { + super("POST", "search_clubs", Response.class); + requestBody = new Body(query); + } + + private static class Body { + public String query; + + public Body(String query) { + this.query = query; + } + } + + public static class Response{ + public List clubs; + } +} diff --git a/Houseclub/src/main/java/me/grishka/houseclub/api/methods/UnfollowClub.java b/Houseclub/src/main/java/me/grishka/houseclub/api/methods/UnfollowClub.java new file mode 100644 index 00000000..d87b5066 --- /dev/null +++ b/Houseclub/src/main/java/me/grishka/houseclub/api/methods/UnfollowClub.java @@ -0,0 +1,19 @@ +package me.grishka.houseclub.api.methods; + +import me.grishka.houseclub.api.BaseResponse; +import me.grishka.houseclub.api.ClubhouseAPIRequest; + +public class UnfollowClub extends ClubhouseAPIRequest{ + public UnfollowClub(int clubId){ + super("POST", "unfollow_club", BaseResponse.class); + requestBody=new Body(clubId); + } + + private static class Body{ + public int clubId, source=4; + + public Body(int clubId){ + this.clubId=clubId; + } + } +} diff --git a/Houseclub/src/main/java/me/grishka/houseclub/api/model/Club.java b/Houseclub/src/main/java/me/grishka/houseclub/api/model/Club.java new file mode 100644 index 00000000..f0f4bfbe --- /dev/null +++ b/Houseclub/src/main/java/me/grishka/houseclub/api/model/Club.java @@ -0,0 +1,80 @@ +package me.grishka.houseclub.api.model; + +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.List; + +public class Club implements Parcelable{ + + public int club_id; + public String name; + public String description; + public String photo_url; + public int num_members; + public int num_followers; + public boolean is_member; + public boolean is_follower; + + + + + @Override + public int describeContents(){ + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags){ + dest.writeInt(this.club_id); + dest.writeString(this.name); + dest.writeString(this.description); + dest.writeString(this.photo_url); + dest.writeInt(this.num_members); + dest.writeInt(this.num_followers); + dest.writeByte(this.is_member ? (byte) 1 : (byte) 0); + dest.writeByte(this.is_follower ? (byte) 1 : (byte) 0); + + + } + + public void readFromParcel(Parcel source){ + this.club_id=source.readInt(); + this.name=source.readString(); + this.description=source.readString(); + this.photo_url=source.readString(); + this.num_members=source.readInt(); + this.num_followers=source.readInt(); + this.is_member=source.readByte()!=0; + this.is_follower=source.readByte()!=0; + + } + + public Club(){ } + + protected Club(Parcel in){ + this.club_id=in.readInt(); + this.name=in.readString(); + this.description=in.readString(); + this.photo_url=in.readString(); + this.num_members=in.readInt(); + this.num_followers=in.readInt(); + this.is_member=in.readByte()!=0; + this.is_follower=in.readByte()!=0; + + + } + + public static final Creator CREATOR=new Creator(){ + @Override + public Club createFromParcel(Parcel source){ + return new Club(source); + } + + @Override + public Club[] newArray(int size){ + return new Club[size]; + } + + }; +} diff --git a/Houseclub/src/main/java/me/grishka/houseclub/api/model/FullUser.java b/Houseclub/src/main/java/me/grishka/houseclub/api/model/FullUser.java index 2132dc13..1c7cdba3 100644 --- a/Houseclub/src/main/java/me/grishka/houseclub/api/model/FullUser.java +++ b/Houseclub/src/main/java/me/grishka/houseclub/api/model/FullUser.java @@ -5,11 +5,13 @@ public class FullUser extends User{ public String dsplayname, bio, twitter, instagram; - public int numFollowers, numFollowing; + public int numFollowers, numFollowing ; public boolean followsMe, isBlockedByNetwork; + public int mutual_follows_count; public Date timeCreated; public User invitedByUserProfile; public List mutualFollows; + public List clubs; // null = not following // 2 = following @@ -19,4 +21,5 @@ public class FullUser extends User{ public boolean isFollowed(){ return notificationType==2; } + } diff --git a/Houseclub/src/main/java/me/grishka/houseclub/api/model/Topic.java b/Houseclub/src/main/java/me/grishka/houseclub/api/model/Topic.java new file mode 100644 index 00000000..c819f8b2 --- /dev/null +++ b/Houseclub/src/main/java/me/grishka/houseclub/api/model/Topic.java @@ -0,0 +1,63 @@ +package me.grishka.houseclub.api.model; + +import android.os.Parcel; +import android.os.Parcelable; + +public class Topic implements Parcelable{ + /* + +"topics": [ + { +"title": "📈 Marketing", +"id": 112, +"abbreviated_title": "Marketing" +}, + + +] + * */ + + public String title; + public int id; + public String abbreviated_title; + + + + @Override + public int describeContents(){ + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags){ + dest.writeString(this.title); + dest.writeInt(this.id); + dest.writeString(this.abbreviated_title); + } + + public void readFromParcel(Parcel source){ + this.title=source.readString(); + this.id=source.readInt(); + this.abbreviated_title=source.readString(); + } + + public Topic(){} + + protected Topic(Parcel in){ + this.title=in.readString(); + this.id=in.readInt(); + this.abbreviated_title=in.readString(); + } + + public static final Creator CREATOR=new Creator(){ + @Override + public Topic createFromParcel(Parcel source){ + return new Topic(source); + } + + @Override + public Topic[] newArray(int size){ + return new Topic[size]; + } + }; +} diff --git a/Houseclub/src/main/java/me/grishka/houseclub/fragments/ClubFragment.java b/Houseclub/src/main/java/me/grishka/houseclub/fragments/ClubFragment.java new file mode 100644 index 00000000..33df89c6 --- /dev/null +++ b/Houseclub/src/main/java/me/grishka/houseclub/fragments/ClubFragment.java @@ -0,0 +1,190 @@ +package me.grishka.houseclub.fragments; + +import android.app.Activity; +import android.app.AlertDialog; +import android.content.DialogInterface; +import android.content.res.Configuration; +import android.graphics.drawable.ColorDrawable; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.ImageView; +import android.widget.TextView; + +import java.util.stream.Collectors; + +import me.grishka.appkit.Nav; +import me.grishka.appkit.api.Callback; +import me.grishka.appkit.api.ErrorResponse; +import me.grishka.appkit.api.SimpleCallback; +import me.grishka.appkit.fragments.LoaderFragment; +import me.grishka.appkit.imageloader.ViewImageLoader; +import me.grishka.houseclub.R; +import me.grishka.houseclub.VoiceService; +import me.grishka.houseclub.api.BaseResponse; +import me.grishka.houseclub.api.ClubhouseSession; +import me.grishka.houseclub.api.methods.FollowClub; +import me.grishka.houseclub.api.methods.GetClub; +import me.grishka.houseclub.api.methods.UnfollowClub; +import me.grishka.houseclub.api.model.Club; + +public class ClubFragment extends LoaderFragment{ + + private static final int PICK_PHOTO_RESULT=468; + + private Club club; + + private boolean is_follower; + private TextView name, description, followers, members, topics , user_clubs; + private ImageView clubPhoto ; + private Button followBtn; + + @Override + public void onAttach(Activity activity){ + super.onAttach(activity); + loadData(); + } + + @Override + public View onCreateContentView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){ + View v=inflater.inflate(R.layout.club, container, false); + + name=v.findViewById(R.id.name); + description=v.findViewById(R.id.description); + followers=v.findViewById(R.id.followers); + members=v.findViewById(R.id.members); + topics=v.findViewById(R.id.topics); + clubPhoto=v.findViewById(R.id.clubPhoto); + + followBtn=v.findViewById(R.id.follow_btn); + + followBtn.setOnClickListener(this::onFollowClick); + + return v; + } + + @Override + protected void doLoadData(){ + + currentRequest=new GetClub(getArguments().getInt("id")) + .setCallback(new SimpleCallback(this){ + @Override + public void onSuccess(GetClub.Response result){ + currentRequest=null; + + club = result.club; + + is_follower = result.is_follower; + + name.setText(club.name); + description.setText(result.club.description); + followers.setText(( club.num_followers>0 ? String.valueOf(club.num_followers) : "0") + " followers"); + members.setText(( club.num_members>0 ? String.valueOf(club.num_members) : "0") + " members"); + + followBtn.setText(is_follower ? R.string.following : R.string.follow); + + topics.setText(result.topics.stream().map(topic->topic.title ).collect(Collectors.joining(" . ")) ); + + if(club.photo_url!=null){ + ColorDrawable d2=new ColorDrawable(getResources().getColor(R.color.grey)); + if(club.photo_url!=null) + ViewImageLoader.load(clubPhoto, d2, club.photo_url); + else + clubPhoto.setImageDrawable(d2); + }else{ + clubPhoto.setVisibility(View.GONE); + } + + + dataLoaded(); + + } + }) + .exec(); + + + + } + + @Override + public void onRefresh(){ + loadData(); + } + + @Override + public void onViewCreated(View view, Bundle savedInstanceState){ + super.onViewCreated(view, savedInstanceState); + getToolbar().setElevation(0); + } + + @Override + public void onConfigurationChanged(Configuration newConfig){ + super.onConfigurationChanged(newConfig); + getToolbar().setElevation(0); + } + + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater){ + menu.add(R.string.log_out); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item){ + if(VoiceService.getInstance()!=null){ + VoiceService.getInstance().leaveChannel(); + } + ClubhouseSession.userID=ClubhouseSession.userToken=null; + ClubhouseSession.write(); + Nav.goClearingStack(getActivity(), LoginFragment.class, null); + return true; + } + + private void onFollowClick(View v){ + if(is_follower){ + new AlertDialog.Builder(getActivity()) + .setMessage(getString(R.string.confirm_unfollow, club.name)) + .setPositiveButton(R.string.yes, new DialogInterface.OnClickListener(){ + @Override + public void onClick(DialogInterface dialogInterface, int i){ + new UnfollowClub(club.club_id) + .wrapProgress(getActivity()) + .setCallback(new Callback(){ + @Override + public void onSuccess(BaseResponse result){ + followBtn.setText(R.string.follow); + } + + @Override + public void onError(ErrorResponse error){ + error.showToast(getActivity()); + } + }) + .exec(); + } + }) + .setNegativeButton(R.string.no, null) + .show(); + }else{ + new FollowClub(club.club_id) + .wrapProgress(getActivity()) + .setCallback(new Callback(){ + @Override + public void onSuccess(BaseResponse result){ + followBtn.setText(R.string.following); + } + + @Override + public void onError(ErrorResponse error){ + error.showToast(getActivity()); + } + }) + .exec(); + } + } + +} diff --git a/Houseclub/src/main/java/me/grishka/houseclub/fragments/ClubListFragment.java b/Houseclub/src/main/java/me/grishka/houseclub/fragments/ClubListFragment.java new file mode 100644 index 00000000..ca7b48d0 --- /dev/null +++ b/Houseclub/src/main/java/me/grishka/houseclub/fragments/ClubListFragment.java @@ -0,0 +1,148 @@ +package me.grishka.houseclub.fragments; + +import android.app.Activity; +import android.content.res.Configuration; +import android.graphics.Bitmap; +import android.graphics.drawable.ColorDrawable; +import android.graphics.drawable.Drawable; +import android.os.Bundle; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + +import me.grishka.appkit.Nav; +import me.grishka.appkit.fragments.BaseRecyclerFragment; +import me.grishka.appkit.imageloader.ImageLoaderRecyclerAdapter; +import me.grishka.appkit.imageloader.ImageLoaderViewHolder; +import me.grishka.appkit.utils.BindableViewHolder; +import me.grishka.appkit.views.UsableRecyclerView; +import me.grishka.houseclub.R; +import me.grishka.houseclub.api.ClubhouseSession; +import me.grishka.houseclub.api.model.Club; + +public abstract class ClubListFragment extends BaseRecyclerFragment{ + + private int selfID = Integer.parseInt(ClubhouseSession.userID); + private ClubListAdapter adapter; + + public ClubListFragment(){ + super(50); + } + + @Override + public void onAttach(Activity activity){ + super.onAttach(activity); + loadData(); + } + + @Override + protected RecyclerView.Adapter getAdapter(){ + if(adapter==null){ + adapter=new ClubListAdapter(); + } + return adapter; + } + + @Override + public void onViewCreated(View view, Bundle savedInstanceState){ + super.onViewCreated(view, savedInstanceState); + getToolbar().setElevation(0); + } + + @Override + public void onConfigurationChanged(Configuration newConfig){ + super.onConfigurationChanged(newConfig); + getToolbar().setElevation(0); + } + + private class ClubListAdapter extends RecyclerView.Adapter implements ImageLoaderRecyclerAdapter{ + + @NonNull + @Override + public ClubViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType){ + return new ClubViewHolder(); + } + + @Override + public void onBindViewHolder(@NonNull ClubViewHolder holder, int position){ + holder.bind(data.get(position)); + } + + @Override + public int getItemCount(){ + return data.size(); + } + + @Override + public int getImageCountForItem(int position) { return data.get(position).photo_url!=null ? 1 : 0;} + + @Override + public String getImageURL(int position, int image) {return data.get(position).photo_url;} + + } + + private class ClubViewHolder extends BindableViewHolder implements ImageLoaderViewHolder, UsableRecyclerView.Clickable{ + + public TextView name, numFollowers, numMembers; + public Button followBtn; + public ImageView photo; + private Drawable placeholder=new ColorDrawable(getResources().getColor(R.color.grey)); + + public ClubViewHolder(){ + super(getActivity(), R.layout.club_list_row); + + name=findViewById(R.id.name); + numFollowers=findViewById(R.id.followersCount); + numMembers=findViewById(R.id.membersCount); + followBtn=findViewById(R.id.follow_btn); + photo=findViewById(R.id.photo); + } + + @Override + public void onBind(Club item){ + name.setText(item.name); + numMembers.setText(item.num_members + " members"); + numFollowers.setText(item.num_followers + " followers"); + + // TODO get_followers/get_following don't return current follow status? +// if(item.userId==selfID){ + followBtn.setVisibility(View.GONE); +// }else{ +// followBtn.setVisibility(View.VISIBLE); +// followBtn.setText(item.isFollowed() ? R.string.following : R.string.follow); +// } + + + if(item.photo_url!=null) + imgLoader.bindViewHolder(adapter, this, getAdapterPosition()); + else + photo.setImageDrawable(placeholder); + + + } + + @Override + public void setImage(int index, Bitmap bitmap){ + photo.setImageBitmap(bitmap); + } + + @Override + public void clearImage(int index){ + photo.setImageDrawable(placeholder); + } + + @Override + public void onClick(){ + Bundle args=new Bundle(); + args.putInt("id", item.club_id); + Nav.go(getActivity(), ClubFragment.class, args); + } + + + } +} diff --git a/Houseclub/src/main/java/me/grishka/houseclub/fragments/EventsFragment.java b/Houseclub/src/main/java/me/grishka/houseclub/fragments/EventsFragment.java index 61900994..d0e4e53b 100644 --- a/Houseclub/src/main/java/me/grishka/houseclub/fragments/EventsFragment.java +++ b/Houseclub/src/main/java/me/grishka/houseclub/fragments/EventsFragment.java @@ -1,34 +1,50 @@ package me.grishka.houseclub.fragments; +import android.Manifest; import android.app.Activity; +import android.app.AlertDialog; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.pm.PackageManager; import android.content.res.Configuration; import android.graphics.Bitmap; import android.graphics.Outline; import android.graphics.Rect; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; +import android.os.Build; import android.os.Bundle; import android.view.View; import android.view.ViewGroup; import android.view.ViewOutlineProvider; import android.widget.ImageView; import android.widget.TextView; +import android.widget.Toast; import androidx.annotation.NonNull; import androidx.recyclerview.widget.RecyclerView; import java.text.DateFormat; import java.text.SimpleDateFormat; +import java.util.Date; import java.util.stream.Collectors; +import me.grishka.appkit.api.Callback; +import me.grishka.appkit.api.ErrorResponse; import me.grishka.appkit.api.SimpleCallback; import me.grishka.appkit.fragments.BaseRecyclerFragment; import me.grishka.appkit.imageloader.ImageLoaderRecyclerAdapter; import me.grishka.appkit.imageloader.ImageLoaderViewHolder; import me.grishka.appkit.utils.BindableViewHolder; import me.grishka.appkit.utils.V; +import me.grishka.houseclub.MainActivity; import me.grishka.houseclub.R; +import me.grishka.houseclub.VoiceService; +import me.grishka.houseclub.api.methods.GetChannel; +import me.grishka.houseclub.api.methods.GetEvent; import me.grishka.houseclub.api.methods.GetEvents; +import me.grishka.houseclub.api.methods.JoinChannel; +import me.grishka.houseclub.api.model.Channel; import me.grishka.houseclub.api.model.Event; public class EventsFragment extends BaseRecyclerFragment{ @@ -200,9 +216,37 @@ public void onBind(Event item){ @Override public void onClick(View view) { + } + private void joinChannelById(String id){ + new GetChannel(id) + .wrapProgress(getActivity()) + .setCallback(new Callback(){ + @Override + public void onSuccess(final Channel result){ + new AlertDialog.Builder(getActivity()) + .setTitle(R.string.join_this_room) + .setMessage(result.topic) + .setPositiveButton(R.string.join, new DialogInterface.OnClickListener(){ + @Override + public void onClick(DialogInterface dialogInterface, int i){ +// joinChannel(result); + } + }) + .setNegativeButton(R.string.cancel, null) + .show(); + } + + @Override + public void onError(ErrorResponse error){ + error.showToast(getActivity()); + } + }) + .exec(); } + + private ImageView imgForIndex(int index){ if(index==0) return pic1; diff --git a/Houseclub/src/main/java/me/grishka/houseclub/fragments/HomeFragment.java b/Houseclub/src/main/java/me/grishka/houseclub/fragments/HomeFragment.java index 2aa0d382..6f9a0d9e 100644 --- a/Houseclub/src/main/java/me/grishka/houseclub/fragments/HomeFragment.java +++ b/Houseclub/src/main/java/me/grishka/houseclub/fragments/HomeFragment.java @@ -147,6 +147,13 @@ else if (item.getItemId() == R.id.homeMenuEvents) { Nav.go(getActivity(), EventsFragment.class, args); return true; } + + else if (item.getItemId() == R.id.homeMenuSearchClubs) { + Bundle args = new Bundle(); + args.putInt("id", Integer.parseInt(ClubhouseSession.userID)); + Nav.go(getActivity(), SearchClubsListFragment.class, args); + return true; + } return super.onOptionsItemSelected(item); } diff --git a/Houseclub/src/main/java/me/grishka/houseclub/fragments/ProfileFragment.java b/Houseclub/src/main/java/me/grishka/houseclub/fragments/ProfileFragment.java index 4768210b..0400e423 100644 --- a/Houseclub/src/main/java/me/grishka/houseclub/fragments/ProfileFragment.java +++ b/Houseclub/src/main/java/me/grishka/houseclub/fragments/ProfileFragment.java @@ -22,6 +22,8 @@ import android.webkit.WebResourceRequest; import android.webkit.WebView; import android.webkit.WebViewClient; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.EditText; import android.widget.ImageView; @@ -48,6 +50,7 @@ import me.grishka.houseclub.api.ClubhouseAPIController; import me.grishka.houseclub.api.ClubhouseSession; import me.grishka.houseclub.api.methods.Follow; +import me.grishka.houseclub.api.methods.GetClub; import me.grishka.houseclub.api.methods.GetProfile; import me.grishka.houseclub.api.methods.InviteToApp; import me.grishka.houseclub.api.methods.Me; @@ -65,7 +68,7 @@ public class ProfileFragment extends LoaderFragment{ private FullUser user; private TextView name, username, followers, following, followsYou, bio, inviteInfo, twitter, instagram, - invites , mutuals , followed_by; + invites , mutuals , followed_by , user_clubs , member_of_text; private ImageView photo, inviterPhoto , pic1 , pic2 , pic3 ; private Button followBtn, inviteButton; private EditText invitePhoneNum; @@ -110,6 +113,8 @@ public View onCreateContentView(LayoutInflater inflater, ViewGroup container, Bu inviteButton = v.findViewById(R.id.invite_button); invites = v.findViewById(R.id.num_of_invites); mutuals = v.findViewById(R.id.mutuals); + user_clubs = v.findViewById(R.id.user_clubs); + member_of_text = v.findViewById(R.id.member_of_text); followed_by = v.findViewById(R.id.followed_by); invitePhoneNum = v.findViewById(R.id.invite_phone_num); @@ -143,7 +148,6 @@ public void onSuccess(GetProfile.Response result){ currentRequest=null; user=result.userProfile; - name.setText(user.name); username.setText('@'+user.username); ColorDrawable d=new ColorDrawable(getResources().getColor(R.color.grey)); @@ -190,11 +194,12 @@ public void onSuccess(GetProfile.Response result){ inviterPhoto.setVisibility(View.GONE); } - if(user.mutualFollows.size() > 0){ + if( user.mutualFollows.size() > 0 ){ followed_by.setText(" Followed by "); String usernames = ""; + for(int i = 0 ; i< user.mutualFollows.size(); i++){ if(i>0){ @@ -233,10 +238,6 @@ public void onSuccess(GetProfile.Response result){ if(i == 2){ - if(user.mutualFollows.size() > 3){ - usernames += "and " + String.valueOf(user.mutualFollows.size() - 3) + "others"; - } - if( user.mutualFollows.get(i).photoUrl !=null){ ColorDrawable d2=new ColorDrawable(getResources().getColor(R.color.grey)); if(user.mutualFollows.get(i).photoUrl!=null) { @@ -253,15 +254,26 @@ public void onSuccess(GetProfile.Response result){ } + if((user.mutual_follows_count - 3) > 0){ + usernames += " and " + (user.mutual_follows_count - 3) + " others"; + } + mutuals.setText(usernames); } inviteInfo.setText(joined); + if(user.clubs.size() > 0){ + + member_of_text.setText("Member of"); + user_clubs.setText(result.userProfile.clubs.stream().map(club->club.name ). + collect(Collectors.joining(" . ")) ); + } + dataLoaded(); @@ -269,6 +281,7 @@ public void onSuccess(GetProfile.Response result){ } }) .exec(); + loadInvites(); } diff --git a/Houseclub/src/main/java/me/grishka/houseclub/fragments/SearchClubsListFragment.java b/Houseclub/src/main/java/me/grishka/houseclub/fragments/SearchClubsListFragment.java new file mode 100644 index 00000000..e12e80d5 --- /dev/null +++ b/Houseclub/src/main/java/me/grishka/houseclub/fragments/SearchClubsListFragment.java @@ -0,0 +1,104 @@ +package me.grishka.houseclub.fragments; + +import android.app.Activity; +import android.os.Bundle; +import android.view.View; +import android.widget.SearchView; + +import me.grishka.appkit.api.SimpleCallback; +import me.grishka.houseclub.R; +import me.grishka.houseclub.api.methods.SearchClubs; + +public class SearchClubsListFragment extends ClubListFragment { + + private SearchView searchView; + private SearchView.OnQueryTextListener onQueryTextListener; + + protected static int min_query_lenght = 2; + protected String searchQuery; + private static final long DELAY = 200; + private long timestamp = System.currentTimeMillis(); + + @Override + public void onAttach(Activity activity){ + super.onAttach(activity); + setTitle(R.string.search_clubs_hint); + } + + @Override + public void onViewCreated(View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + + View search_panel = view.inflate(getContext(), R.layout.search_panel, null); + + searchView = search_panel.findViewById(R.id.searchView); + searchView.setQueryHint(getString(R.string.search_clubs_hint)); + onQueryTextListener = new OnSearchQueryTextListener(); + + getToolbar().addView(search_panel); + } + + protected void onQueryChanged(String query) { + long currentTimeStamp = System.currentTimeMillis(); + if (currentTimeStamp - timestamp < DELAY) { + timestamp = currentTimeStamp; + return; + } + + if (query == null && min_query_lenght > 0 || query.length() <= min_query_lenght) { + timestamp = currentTimeStamp; + return; + } + timestamp = currentTimeStamp; + searchQuery = query; + loadData(); + } + + private class OnSearchQueryTextListener implements SearchView.OnQueryTextListener { + @Override + public boolean onQueryTextSubmit(String query) { + onQueryChanged(query); + return false; + } + + @Override + public boolean onQueryTextChange(String newText) { + onQueryChanged(newText); + return false; + } + } + + @Override + public void onResume() { + super.onResume(); + searchView.setOnQueryTextListener(onQueryTextListener); + } + + @Override + public void onPause() { + super.onPause(); + searchView.setOnQueryTextListener(null); + } + + @Override + protected void doLoadData(int offset, int count) { + if (currentRequest != null) { + currentRequest.cancel(); + } + + currentRequest = new SearchClubs(searchQuery) + .setCallback(new SimpleCallback(this) { + @Override + public void onSuccess(SearchClubs.Response result) { + currentRequest=null; + data.clear(); + onDataLoaded(result.clubs , false); + } + + }).exec(); + } + + + + +} diff --git a/Houseclub/src/main/res/drawable/ic_baseline_person_add_24.xml b/Houseclub/src/main/res/drawable/ic_baseline_person_add_24.xml new file mode 100644 index 00000000..e918a98f --- /dev/null +++ b/Houseclub/src/main/res/drawable/ic_baseline_person_add_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/Houseclub/src/main/res/drawable/ic_baseline_person_search_24.xml b/Houseclub/src/main/res/drawable/ic_baseline_person_search_24.xml new file mode 100644 index 00000000..bac61cb9 --- /dev/null +++ b/Houseclub/src/main/res/drawable/ic_baseline_person_search_24.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/Houseclub/src/main/res/layout/club.xml b/Houseclub/src/main/res/layout/club.xml new file mode 100644 index 00000000..0c0cef6f --- /dev/null +++ b/Houseclub/src/main/res/layout/club.xml @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + +