Browse Source
Add account switcher in MorePreferencesFragment
renovate/org.robolectric-robolectric-4.x
Add account switcher in MorePreferencesFragment
renovate/org.robolectric-robolectric-4.x
Ammar Githam
4 years ago
24 changed files with 761 additions and 155 deletions
-
41app/src/main/java/awais/instagrabber/activities/Login.java
-
5app/src/main/java/awais/instagrabber/activities/MainActivity.java
-
112app/src/main/java/awais/instagrabber/adapters/AccountSwitcherListAdapter.java
-
14app/src/main/java/awais/instagrabber/dialogs/QuickAccessDialog.java
-
21app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java
-
223app/src/main/java/awais/instagrabber/fragments/settings/MorePreferencesFragment.java
-
7app/src/main/java/awais/instagrabber/fragments/settings/SettingsPreferencesFragment.java
-
11app/src/main/java/awais/instagrabber/repositories/ProfileRepository.java
-
41app/src/main/java/awais/instagrabber/repositories/responses/UserInfo.java
-
3app/src/main/java/awais/instagrabber/services/AddCookiesInterceptor.java
-
4app/src/main/java/awais/instagrabber/services/FeedService.java
-
2app/src/main/java/awais/instagrabber/services/FriendshipService.java
-
18app/src/main/java/awais/instagrabber/services/LoggingInterceptor.java
-
69app/src/main/java/awais/instagrabber/services/ProfileService.java
-
195app/src/main/java/awais/instagrabber/utils/DataBox.java
-
51app/src/main/java/awais/instagrabber/utils/ExportImportUtils.java
-
8app/src/main/java/awais/instagrabber/utils/NavigationExtensions.java
-
1app/src/main/java/awais/instagrabber/utils/Utils.java
-
10app/src/main/res/drawable/ic_arrow_drop_down_24.xml
-
10app/src/main/res/drawable/ic_check_24.xml
-
65app/src/main/res/layout/pref_account_switcher.xml
-
1app/src/main/res/values/arrays.xml
-
1app/src/main/res/values/dimens.xml
-
3app/src/main/res/values/strings.xml
@ -0,0 +1,112 @@ |
|||||
|
package awais.instagrabber.adapters; |
||||
|
|
||||
|
import android.annotation.SuppressLint; |
||||
|
import android.content.Context; |
||||
|
import android.graphics.Typeface; |
||||
|
import android.text.TextUtils; |
||||
|
import android.view.LayoutInflater; |
||||
|
import android.view.View; |
||||
|
import android.view.ViewGroup; |
||||
|
import android.widget.ArrayAdapter; |
||||
|
|
||||
|
import androidx.annotation.NonNull; |
||||
|
import androidx.annotation.Nullable; |
||||
|
|
||||
|
import java.util.List; |
||||
|
|
||||
|
import awais.instagrabber.R; |
||||
|
import awais.instagrabber.databinding.PrefAccountSwitcherBinding; |
||||
|
import awais.instagrabber.utils.Constants; |
||||
|
import awais.instagrabber.utils.DataBox; |
||||
|
|
||||
|
import static awais.instagrabber.utils.Utils.settingsHelper; |
||||
|
|
||||
|
public class AccountSwitcherListAdapter extends ArrayAdapter<DataBox.CookieModel> { |
||||
|
private static final String TAG = "AccountSwitcherListAdap"; |
||||
|
|
||||
|
private final OnAccountClickListener clickListener; |
||||
|
private final OnAccountLongClickListener longClickListener; |
||||
|
|
||||
|
public AccountSwitcherListAdapter(@NonNull final Context context, |
||||
|
final int resource, |
||||
|
@NonNull final List<DataBox.CookieModel> allUsers, |
||||
|
final OnAccountClickListener clickListener, |
||||
|
final OnAccountLongClickListener longClickListener) { |
||||
|
super(context, resource, allUsers); |
||||
|
this.clickListener = clickListener; |
||||
|
this.longClickListener = longClickListener; |
||||
|
} |
||||
|
|
||||
|
@NonNull |
||||
|
@Override |
||||
|
public View getView(final int position, @Nullable final View convertView, @NonNull final ViewGroup parent) { |
||||
|
final DataBox.CookieModel model = getItem(position); |
||||
|
final String cookie = settingsHelper.getString(Constants.COOKIE); |
||||
|
if (convertView == null) { |
||||
|
final LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext()); |
||||
|
final PrefAccountSwitcherBinding binding = PrefAccountSwitcherBinding.inflate(layoutInflater, parent, false); |
||||
|
final ViewHolder viewHolder = new ViewHolder(binding); |
||||
|
viewHolder.itemView.setTag(viewHolder); |
||||
|
if (model == null) return viewHolder.itemView; |
||||
|
final boolean equals = model.getCookie().equals(cookie); |
||||
|
viewHolder.bind(model, equals, clickListener, longClickListener); |
||||
|
return viewHolder.itemView; |
||||
|
} |
||||
|
final ViewHolder viewHolder = (ViewHolder) convertView.getTag(); |
||||
|
if (model == null) return viewHolder.itemView; |
||||
|
final boolean equals = model.getCookie().equals(cookie); |
||||
|
viewHolder.bind(model, equals, clickListener, longClickListener); |
||||
|
return viewHolder.itemView; |
||||
|
} |
||||
|
|
||||
|
public interface OnAccountClickListener { |
||||
|
void onAccountClick(final DataBox.CookieModel model, final boolean isCurrent); |
||||
|
} |
||||
|
|
||||
|
public interface OnAccountLongClickListener { |
||||
|
boolean onAccountLongClick(final DataBox.CookieModel model, final boolean isCurrent); |
||||
|
} |
||||
|
|
||||
|
private static class ViewHolder { |
||||
|
private final View itemView; |
||||
|
private final PrefAccountSwitcherBinding binding; |
||||
|
|
||||
|
public ViewHolder(final PrefAccountSwitcherBinding binding) { |
||||
|
this.itemView = binding.getRoot(); |
||||
|
this.binding = binding; |
||||
|
binding.arrowDown.setImageResource(R.drawable.ic_check_24); |
||||
|
} |
||||
|
|
||||
|
@SuppressLint("SetTextI18n") |
||||
|
public void bind(final DataBox.CookieModel model, |
||||
|
final boolean isCurrent, |
||||
|
final OnAccountClickListener clickListener, |
||||
|
final OnAccountLongClickListener longClickListener) { |
||||
|
// Log.d(TAG, model.getFullName()); |
||||
|
itemView.setOnClickListener(v -> { |
||||
|
if (clickListener == null) return; |
||||
|
clickListener.onAccountClick(model, isCurrent); |
||||
|
}); |
||||
|
itemView.setOnLongClickListener(v -> { |
||||
|
if (longClickListener == null) return false; |
||||
|
return longClickListener.onAccountLongClick(model, isCurrent); |
||||
|
}); |
||||
|
binding.profilePic.setImageURI(model.getProfilePic()); |
||||
|
binding.username.setText("@" + model.getUsername()); |
||||
|
binding.fullName.setTypeface(null); |
||||
|
final String fullName = model.getFullName(); |
||||
|
if (TextUtils.isEmpty(fullName)) { |
||||
|
binding.fullName.setVisibility(View.GONE); |
||||
|
} else { |
||||
|
binding.fullName.setVisibility(View.VISIBLE); |
||||
|
binding.fullName.setText(fullName); |
||||
|
} |
||||
|
if (!isCurrent) { |
||||
|
binding.arrowDown.setVisibility(View.GONE); |
||||
|
return; |
||||
|
} |
||||
|
binding.fullName.setTypeface(binding.fullName.getTypeface(), Typeface.BOLD); |
||||
|
binding.arrowDown.setVisibility(View.VISIBLE); |
||||
|
} |
||||
|
} |
||||
|
} |
@ -0,0 +1,11 @@ |
|||||
|
package awais.instagrabber.repositories; |
||||
|
|
||||
|
import retrofit2.Call; |
||||
|
import retrofit2.http.GET; |
||||
|
import retrofit2.http.Path; |
||||
|
|
||||
|
public interface ProfileRepository { |
||||
|
|
||||
|
@GET("api/v1/users/{uid}/info/") |
||||
|
Call<String> getUserInfo(@Path("uid") final String uid); |
||||
|
} |
@ -0,0 +1,41 @@ |
|||||
|
package awais.instagrabber.repositories.responses; |
||||
|
|
||||
|
public class UserInfo { |
||||
|
private final String pk; |
||||
|
private final String username; |
||||
|
private final String fullName; |
||||
|
private final String profilePicUrl; |
||||
|
|
||||
|
public UserInfo(final String pk, final String username, final String fullName, final String profilePicUrl) { |
||||
|
this.pk = pk; |
||||
|
this.username = username; |
||||
|
this.fullName = fullName; |
||||
|
this.profilePicUrl = profilePicUrl; |
||||
|
} |
||||
|
|
||||
|
public String getPk() { |
||||
|
return pk; |
||||
|
} |
||||
|
|
||||
|
public String getUsername() { |
||||
|
return username; |
||||
|
} |
||||
|
|
||||
|
public String getFullName() { |
||||
|
return fullName; |
||||
|
} |
||||
|
|
||||
|
public String getProfilePicUrl() { |
||||
|
return profilePicUrl; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public String toString() { |
||||
|
return "UserInfo{" + |
||||
|
"uid='" + pk + '\'' + |
||||
|
", username='" + username + '\'' + |
||||
|
", fullName='" + fullName + '\'' + |
||||
|
", profilePicUrl='" + profilePicUrl + '\'' + |
||||
|
'}'; |
||||
|
} |
||||
|
} |
@ -1,4 +0,0 @@ |
|||||
package awais.instagrabber.services; |
|
||||
|
|
||||
public interface FeedService { |
|
||||
} |
|
@ -0,0 +1,69 @@ |
|||||
|
package awais.instagrabber.services; |
||||
|
|
||||
|
import android.util.Log; |
||||
|
|
||||
|
import androidx.annotation.NonNull; |
||||
|
|
||||
|
import org.json.JSONException; |
||||
|
import org.json.JSONObject; |
||||
|
|
||||
|
import awais.instagrabber.repositories.ProfileRepository; |
||||
|
import awais.instagrabber.repositories.responses.UserInfo; |
||||
|
import awais.instagrabber.utils.Constants; |
||||
|
import retrofit2.Call; |
||||
|
import retrofit2.Callback; |
||||
|
import retrofit2.Response; |
||||
|
import retrofit2.Retrofit; |
||||
|
|
||||
|
public class ProfileService extends BaseService { |
||||
|
private static final String TAG = "ProfileService"; |
||||
|
|
||||
|
private final ProfileRepository repository; |
||||
|
|
||||
|
private static ProfileService instance; |
||||
|
|
||||
|
private ProfileService() { |
||||
|
final Retrofit retrofit = getRetrofitBuilder() |
||||
|
.baseUrl("https://i.instagram.com") |
||||
|
.build(); |
||||
|
repository = retrofit.create(ProfileRepository.class); |
||||
|
} |
||||
|
|
||||
|
public static ProfileService getInstance() { |
||||
|
if (instance == null) { |
||||
|
instance = new ProfileService(); |
||||
|
} |
||||
|
return instance; |
||||
|
} |
||||
|
|
||||
|
public void getUserInfo(final String uid, final ServiceCallback<UserInfo> callback) { |
||||
|
final Call<String> request = repository.getUserInfo(uid); |
||||
|
request.enqueue(new Callback<String>() { |
||||
|
@Override |
||||
|
public void onResponse(@NonNull final Call<String> call, @NonNull final Response<String> response) { |
||||
|
final String body = response.body(); |
||||
|
if (body == null) return; |
||||
|
try { |
||||
|
final JSONObject jsonObject = new JSONObject(body); |
||||
|
final JSONObject user = jsonObject.optJSONObject(Constants.EXTRAS_USER); |
||||
|
if (user == null) return; |
||||
|
// Log.d(TAG, "user: " + user.toString()); |
||||
|
final UserInfo userInfo = new UserInfo( |
||||
|
uid, |
||||
|
user.getString(Constants.EXTRAS_USERNAME), |
||||
|
user.optString("full_name"), |
||||
|
user.optString("profile_pic_url") |
||||
|
); |
||||
|
callback.onSuccess(userInfo); |
||||
|
} catch (JSONException e) { |
||||
|
Log.e(TAG, "Error parsing json", e); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void onFailure(@NonNull final Call<String> call, @NonNull final Throwable t) { |
||||
|
callback.onFailure(t); |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
} |
@ -0,0 +1,10 @@ |
|||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android" |
||||
|
android:width="24dp" |
||||
|
android:height="24dp" |
||||
|
android:viewportWidth="24" |
||||
|
android:viewportHeight="24" |
||||
|
android:tint="?attr/colorControlNormal"> |
||||
|
<path |
||||
|
android:fillColor="@android:color/white" |
||||
|
android:pathData="M7,10l5,5 5,-5z"/> |
||||
|
</vector> |
@ -0,0 +1,10 @@ |
|||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android" |
||||
|
android:width="24dp" |
||||
|
android:height="24dp" |
||||
|
android:viewportWidth="24" |
||||
|
android:viewportHeight="24" |
||||
|
android:tint="?attr/colorControlNormal"> |
||||
|
<path |
||||
|
android:fillColor="@android:color/white" |
||||
|
android:pathData="M9,16.17L4.83,12l-1.42,1.41L9,19 21,7l-1.41,-1.41z"/> |
||||
|
</vector> |
@ -0,0 +1,65 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" |
||||
|
xmlns:app="http://schemas.android.com/apk/res-auto" |
||||
|
xmlns:tools="http://schemas.android.com/tools" |
||||
|
android:layout_width="match_parent" |
||||
|
android:layout_height="wrap_content" |
||||
|
android:background="?attr/selectableItemBackground" |
||||
|
android:clickable="true" |
||||
|
android:focusable="true" |
||||
|
android:padding="16dp"> |
||||
|
|
||||
|
<com.facebook.drawee.view.SimpleDraweeView |
||||
|
android:id="@+id/profile_pic" |
||||
|
android:layout_width="@dimen/image_size_40" |
||||
|
android:layout_height="@dimen/image_size_40" |
||||
|
android:scaleType="centerCrop" |
||||
|
app:layout_constraintStart_toStartOf="parent" |
||||
|
app:layout_constraintTop_toTopOf="parent" |
||||
|
app:roundAsCircle="true" /> |
||||
|
|
||||
|
<androidx.appcompat.widget.AppCompatTextView |
||||
|
android:id="@+id/full_name" |
||||
|
android:layout_width="0dp" |
||||
|
android:layout_height="0dp" |
||||
|
android:gravity="center_vertical" |
||||
|
android:paddingStart="16dp" |
||||
|
android:paddingLeft="16dp" |
||||
|
android:paddingEnd="16dp" |
||||
|
android:paddingRight="16dp" |
||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Body1" |
||||
|
android:textStyle="bold" |
||||
|
app:layout_constraintBottom_toTopOf="@id/username" |
||||
|
app:layout_constraintEnd_toStartOf="@id/arrow_down" |
||||
|
app:layout_constraintStart_toEndOf="@id/profile_pic" |
||||
|
app:layout_constraintTop_toTopOf="parent" |
||||
|
tools:text="full name" /> |
||||
|
|
||||
|
<androidx.appcompat.widget.AppCompatTextView |
||||
|
android:id="@+id/username" |
||||
|
android:layout_width="0dp" |
||||
|
android:layout_height="0dp" |
||||
|
android:gravity="center_vertical" |
||||
|
android:paddingStart="16dp" |
||||
|
android:paddingLeft="16dp" |
||||
|
android:paddingEnd="16dp" |
||||
|
android:paddingRight="16dp" |
||||
|
app:layout_constraintBottom_toBottomOf="parent" |
||||
|
app:layout_constraintEnd_toStartOf="@id/arrow_down" |
||||
|
app:layout_constraintStart_toEndOf="@id/profile_pic" |
||||
|
app:layout_constraintTop_toBottomOf="@id/full_name" |
||||
|
tools:text="\@username" /> |
||||
|
|
||||
|
<androidx.appcompat.widget.AppCompatImageView |
||||
|
android:id="@+id/arrow_down" |
||||
|
android:layout_width="wrap_content" |
||||
|
android:layout_height="wrap_content" |
||||
|
android:padding="8dp" |
||||
|
app:layout_constraintBottom_toBottomOf="parent" |
||||
|
app:layout_constraintEnd_toEndOf="parent" |
||||
|
app:layout_constraintStart_toEndOf="@id/full_name" |
||||
|
app:layout_constraintTop_toTopOf="parent" |
||||
|
app:srcCompat="@drawable/ic_arrow_drop_down_24" |
||||
|
app:tint="?colorAccent" /> |
||||
|
|
||||
|
</androidx.constraintlayout.widget.ConstraintLayout> |
Write
Preview
Loading…
Cancel
Save
Reference in new issue