Add profile repo to user profile, add ssh keys listing, new account settings screen and clean up

This commit is contained in:
M M Arif 2023-09-19 22:53:36 +05:00
parent 7a89a04bb8
commit 5c0f494b2c
28 changed files with 1097 additions and 1165 deletions

View File

@ -52,7 +52,7 @@
android:name=".activities.CreateNewUserActivity"
android:configChanges="orientation|screenSize|smallestScreenSize|density|screenLayout|keyboard|keyboardHidden|navigation"/>
<activity
android:name=".activities.MyProfileEmailActivity"
android:name=".activities.AccountSettingsEmailActivity"
android:configChanges="orientation|screenSize|smallestScreenSize|density|screenLayout|keyboard|keyboardHidden|navigation"/>
<activity
android:name=".activities.AddCollaboratorToRepositoryActivity"

View File

@ -6,19 +6,17 @@ import android.util.Log;
import android.util.Patterns;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import androidx.annotation.NonNull;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import org.gitnex.tea4j.v2.models.CreateEmailOption;
import org.gitnex.tea4j.v2.models.Email;
import org.mian.gitnex.R;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.databinding.ActivityProfileEmailBinding;
import org.mian.gitnex.fragments.MyProfileEmailsFragment;
import org.mian.gitnex.databinding.ActivityAccountSettingsEmailBinding;
import org.mian.gitnex.fragments.AccountSettingsEmailsFragment;
import org.mian.gitnex.helpers.AlertDialogs;
import org.mian.gitnex.helpers.AppUtil;
import org.mian.gitnex.helpers.Toasty;
@ -28,44 +26,40 @@ import retrofit2.Callback;
/**
* @author M M Arif
*/
public class MyProfileEmailActivity extends BaseActivity {
public class AccountSettingsEmailActivity extends BaseActivity {
private View.OnClickListener onClickListener;
private EditText userEmail;
private Button addEmailButton;
private final View.OnClickListener addEmailListener = v -> processAddNewEmail();
private ActivityAccountSettingsEmailBinding activityAccountSettingsEmailBinding;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityProfileEmailBinding activityProfileEmailBinding =
ActivityProfileEmailBinding.inflate(getLayoutInflater());
setContentView(activityProfileEmailBinding.getRoot());
activityAccountSettingsEmailBinding =
ActivityAccountSettingsEmailBinding.inflate(getLayoutInflater());
setContentView(activityAccountSettingsEmailBinding.getRoot());
boolean connToInternet = AppUtil.hasNetworkConnection(appCtx);
InputMethodManager imm =
(InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
ImageView closeActivity = activityProfileEmailBinding.close;
userEmail = activityProfileEmailBinding.userEmail;
addEmailButton = activityProfileEmailBinding.addEmailButton;
userEmail.requestFocus();
activityAccountSettingsEmailBinding.userEmail.requestFocus();
assert imm != null;
imm.showSoftInput(userEmail, InputMethodManager.SHOW_IMPLICIT);
imm.showSoftInput(
activityAccountSettingsEmailBinding.userEmail, InputMethodManager.SHOW_IMPLICIT);
initCloseListener();
closeActivity.setOnClickListener(onClickListener);
activityAccountSettingsEmailBinding.close.setOnClickListener(onClickListener);
if (!connToInternet) {
disableProcessButton();
} else {
addEmailButton.setOnClickListener(addEmailListener);
activityAccountSettingsEmailBinding.addEmailButton.setOnClickListener(addEmailListener);
}
}
@ -73,7 +67,10 @@ public class MyProfileEmailActivity extends BaseActivity {
boolean connToInternet = AppUtil.hasNetworkConnection(appCtx);
String newUserEmail = userEmail.getText().toString().trim();
String newUserEmail =
Objects.requireNonNull(activityAccountSettingsEmailBinding.userEmail.getText())
.toString()
.trim();
if (!connToInternet) {
@ -115,7 +112,7 @@ public class MyProfileEmailActivity extends BaseActivity {
if (response.code() == 201) {
Toasty.success(ctx, getString(R.string.emailAddedText));
MyProfileEmailsFragment.refreshEmails = true;
AccountSettingsEmailsFragment.refreshEmails = true;
enableProcessButton();
finish();
} else if (response.code() == 401) {
@ -157,11 +154,11 @@ public class MyProfileEmailActivity extends BaseActivity {
private void disableProcessButton() {
addEmailButton.setEnabled(false);
activityAccountSettingsEmailBinding.addEmailButton.setEnabled(false);
}
private void enableProcessButton() {
addEmailButton.setEnabled(true);
activityAccountSettingsEmailBinding.addEmailButton.setEnabled(true);
}
}

View File

@ -36,6 +36,7 @@ import org.mian.gitnex.database.api.BaseApi;
import org.mian.gitnex.database.api.UserAccountsApi;
import org.mian.gitnex.database.models.UserAccount;
import org.mian.gitnex.databinding.ActivityMainBinding;
import org.mian.gitnex.fragments.AccountSettingsFragment;
import org.mian.gitnex.fragments.AdministrationFragment;
import org.mian.gitnex.fragments.BottomSheetDraftsFragment;
import org.mian.gitnex.fragments.BottomSheetMyIssuesFilterFragment;
@ -44,7 +45,6 @@ import org.mian.gitnex.fragments.DraftsFragment;
import org.mian.gitnex.fragments.ExploreFragment;
import org.mian.gitnex.fragments.MostVisitedReposFragment;
import org.mian.gitnex.fragments.MyIssuesFragment;
import org.mian.gitnex.fragments.MyProfileFragment;
import org.mian.gitnex.fragments.MyRepositoriesFragment;
import org.mian.gitnex.fragments.NotesFragment;
import org.mian.gitnex.fragments.NotificationsFragment;
@ -85,6 +85,7 @@ public class MainActivity extends BaseActivity
private BottomSheetListener profileInitListener;
private FragmentRefreshListener fragmentRefreshListenerMyIssues;
private String username;
@Override
public void onCreate(Bundle savedInstanceState) {
@ -139,8 +140,8 @@ public class MainActivity extends BaseActivity
toolbarTitle.setText(getResources().getString(R.string.pageTitleExplore));
} else if (fragmentById instanceof NotificationsFragment) {
toolbarTitle.setText(R.string.pageTitleNotifications);
} else if (fragmentById instanceof MyProfileFragment) {
toolbarTitle.setText(getResources().getString(R.string.navProfile));
} else if (fragmentById instanceof AccountSettingsFragment) {
toolbarTitle.setText(getResources().getString(R.string.navAccount));
} else if (fragmentById instanceof MostVisitedReposFragment) {
toolbarTitle.setText(getResources().getString(R.string.navMostVisited));
} else if (fragmentById instanceof NotesFragment) {
@ -241,6 +242,7 @@ public class MainActivity extends BaseActivity
userFullName.setTypeface(myTypeface);
if (getAccount().getUserInfo() != null) {
username = getAccount().getUserInfo().getLogin();
String userEmailNav = getAccount().getUserInfo().getEmail();
String userFullNameNav = getAccount().getFullName();
String userAvatarNav = getAccount().getUserInfo().getAvatarUrl();
@ -270,15 +272,9 @@ public class MainActivity extends BaseActivity
userAvatar.setOnClickListener(
v -> {
toolbarTitle.setText(
getResources().getString(R.string.navProfile));
getSupportFragmentManager()
.beginTransaction()
.replace(
R.id.fragment_container,
new MyProfileFragment())
.commit();
navigationView.setCheckedItem(R.id.nav_profile);
Intent intentProfile = new Intent(ctx, ProfileActivity.class);
intentProfile.putExtra("username", username);
ctx.startActivity(intentProfile);
drawer.closeDrawers();
});
@ -388,11 +384,9 @@ public class MainActivity extends BaseActivity
return;
case "profile":
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.fragment_container, new MyProfileFragment())
.commit();
navigationView.setCheckedItem(R.id.nav_profile);
Intent intentProfile = new Intent(ctx, ProfileActivity.class);
intentProfile.putExtra("username", username);
ctx.startActivity(intentProfile);
return;
case "admin":
@ -442,12 +436,12 @@ public class MainActivity extends BaseActivity
break;
case 4:
toolbarTitle.setText(getResources().getString(R.string.navProfile));
toolbarTitle.setText(getResources().getString(R.string.navAccount));
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.fragment_container, new MyProfileFragment())
.replace(R.id.fragment_container, new AccountSettingsFragment())
.commit();
navigationView.setCheckedItem(R.id.nav_profile);
navigationView.setCheckedItem(R.id.nav_account_settings);
break;
case 5:
@ -654,11 +648,11 @@ public class MainActivity extends BaseActivity
.replace(R.id.fragment_container, new OrganizationsFragment())
.commit();
} else if (id == R.id.nav_profile) {
toolbarTitle.setText(getResources().getString(R.string.navProfile));
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.fragment_container, new MyProfileFragment())
.commit();
Intent intentProfile = new Intent(ctx, ProfileActivity.class);
intentProfile.putExtra("username", username);
ctx.startActivity(intentProfile);
drawer.closeDrawers();
} else if (id == R.id.nav_repositories) {
toolbarTitle.setText(getResources().getString(R.string.navRepos));
@ -736,6 +730,13 @@ public class MainActivity extends BaseActivity
.beginTransaction()
.replace(R.id.fragment_container, new DashboardFragment())
.commit();
} else if (id == R.id.nav_account_settings) {
toolbarTitle.setText(getResources().getString(R.string.navAccount));
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.fragment_container, new AccountSettingsFragment())
.commit();
}
drawer.closeDrawer(GravityCompat.START);

View File

@ -147,7 +147,7 @@ public class ProfileActivity extends BaseActivity implements BottomSheetListener
}
call.enqueue(
new Callback<Void>() {
new Callback<>() {
@Override
public void onResponse(

View File

@ -17,29 +17,29 @@ import org.mian.gitnex.R;
/**
* @author M M Arif
*/
public class MyProfileEmailsAdapter
extends RecyclerView.Adapter<MyProfileEmailsAdapter.EmailsViewHolder> {
public class AccountSettingsEmailsAdapter
extends RecyclerView.Adapter<AccountSettingsEmailsAdapter.EmailsViewHolder> {
private final List<Email> emailsList;
private final Context context;
public MyProfileEmailsAdapter(Context ctx, List<Email> emailsListMain) {
public AccountSettingsEmailsAdapter(Context ctx, List<Email> emailsListMain) {
this.context = ctx;
this.emailsList = emailsListMain;
}
@NonNull @Override
public MyProfileEmailsAdapter.EmailsViewHolder onCreateViewHolder(
public AccountSettingsEmailsAdapter.EmailsViewHolder onCreateViewHolder(
@NonNull ViewGroup parent, int viewType) {
View v =
LayoutInflater.from(parent.getContext())
.inflate(R.layout.list_profile_emails, parent, false);
return new MyProfileEmailsAdapter.EmailsViewHolder(v);
.inflate(R.layout.list_account_settings_emails, parent, false);
return new AccountSettingsEmailsAdapter.EmailsViewHolder(v);
}
@Override
public void onBindViewHolder(
@NonNull MyProfileEmailsAdapter.EmailsViewHolder holder, int position) {
@NonNull AccountSettingsEmailsAdapter.EmailsViewHolder holder, int position) {
Email currentItem = emailsList.get(position);

View File

@ -0,0 +1,59 @@
package org.mian.gitnex.adapters;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import java.util.List;
import org.gitnex.tea4j.v2.models.PublicKey;
import org.mian.gitnex.R;
/**
* @author M M Arif
*/
public class SSHKeysAdapter extends RecyclerView.Adapter<SSHKeysAdapter.KeysViewHolder> {
private final List<PublicKey> keysList;
public SSHKeysAdapter(List<PublicKey> keysListMain) {
this.keysList = keysListMain;
}
@NonNull @Override
public SSHKeysAdapter.KeysViewHolder onCreateViewHolder(
@NonNull ViewGroup parent, int viewType) {
View v =
LayoutInflater.from(parent.getContext())
.inflate(R.layout.list_account_settings_ssh_keys, parent, false);
return new SSHKeysAdapter.KeysViewHolder(v);
}
@Override
public void onBindViewHolder(@NonNull SSHKeysAdapter.KeysViewHolder holder, int position) {
PublicKey currentItem = keysList.get(position);
holder.keyName.setText(currentItem.getTitle());
holder.key.setText(currentItem.getKey());
}
@Override
public int getItemCount() {
return keysList.size();
}
static class KeysViewHolder extends RecyclerView.ViewHolder {
private final TextView keyName;
private final TextView key;
private KeysViewHolder(View itemView) {
super(itemView);
keyName = itemView.findViewById(R.id.keyName);
key = itemView.findViewById(R.id.key);
}
}
}

View File

@ -0,0 +1,104 @@
package org.mian.gitnex.fragments;
import android.annotation.SuppressLint;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import org.mian.gitnex.activities.AccountSettingsEmailActivity;
import org.mian.gitnex.adapters.AccountSettingsEmailsAdapter;
import org.mian.gitnex.databinding.FragmentAccountSettingsEmailsBinding;
import org.mian.gitnex.viewmodels.AccountSettingsEmailsViewModel;
/**
* @author M M Arif
*/
public class AccountSettingsEmailsFragment extends Fragment {
public static boolean refreshEmails = false;
private AccountSettingsEmailsViewModel accountSettingsEmailsViewModel;
private AccountSettingsEmailsAdapter adapter;
public AccountSettingsEmailsFragment() {}
private FragmentAccountSettingsEmailsBinding fragmentAccountSettingsEmailsBinding;
@Override
public View onCreateView(
@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
fragmentAccountSettingsEmailsBinding =
FragmentAccountSettingsEmailsBinding.inflate(inflater, container, false);
accountSettingsEmailsViewModel =
new ViewModelProvider(this).get(AccountSettingsEmailsViewModel.class);
final SwipeRefreshLayout swipeRefresh = fragmentAccountSettingsEmailsBinding.pullToRefresh;
fragmentAccountSettingsEmailsBinding.recyclerView.setHasFixedSize(true);
fragmentAccountSettingsEmailsBinding.recyclerView.setLayoutManager(
new LinearLayoutManager(getContext()));
swipeRefresh.setOnRefreshListener(
() ->
new Handler(Looper.getMainLooper())
.postDelayed(
() -> {
swipeRefresh.setRefreshing(false);
accountSettingsEmailsViewModel.loadEmailsList(
getContext());
},
200));
fetchDataAsync();
fragmentAccountSettingsEmailsBinding.addNewEmailAddress.setOnClickListener(
v1 -> startActivity(new Intent(getContext(), AccountSettingsEmailActivity.class)));
return fragmentAccountSettingsEmailsBinding.getRoot();
}
@SuppressLint("NotifyDataSetChanged")
private void fetchDataAsync() {
accountSettingsEmailsViewModel
.getEmailsList(getContext())
.observe(
getViewLifecycleOwner(),
emailsListMain -> {
adapter =
new AccountSettingsEmailsAdapter(getContext(), emailsListMain);
if (adapter.getItemCount() > 0) {
fragmentAccountSettingsEmailsBinding.recyclerView.setAdapter(
adapter);
fragmentAccountSettingsEmailsBinding.noDataEmails.setVisibility(
View.GONE);
} else {
adapter.notifyDataSetChanged();
fragmentAccountSettingsEmailsBinding.recyclerView.setAdapter(
adapter);
fragmentAccountSettingsEmailsBinding.noDataEmails.setVisibility(
View.VISIBLE);
}
fragmentAccountSettingsEmailsBinding.progressBar.setVisibility(
View.GONE);
});
}
@Override
public void onResume() {
super.onResume();
if (refreshEmails) {
accountSettingsEmailsViewModel.loadEmailsList(getContext());
refreshEmails = false;
}
}
}

View File

@ -0,0 +1,131 @@
package org.mian.gitnex.fragments;
import android.content.Context;
import android.graphics.Typeface;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.viewpager2.adapter.FragmentStateAdapter;
import androidx.viewpager2.widget.ViewPager2;
import com.google.android.material.tabs.TabLayout;
import com.google.android.material.tabs.TabLayoutMediator;
import org.mian.gitnex.R;
import org.mian.gitnex.activities.BaseActivity;
import org.mian.gitnex.activities.MainActivity;
import org.mian.gitnex.helpers.AppUtil;
import org.mian.gitnex.helpers.contexts.AccountContext;
/**
* @author M M Arif
*/
public class AccountSettingsFragment extends Fragment {
public ViewPager2 viewPager;
private Context ctx;
private View view;
private Typeface myTypeface;
@Nullable @Override
public View onCreateView(
@NonNull LayoutInflater inflater,
@Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
ctx = getContext();
view = inflater.inflate(R.layout.fragment_account_settings, container, false);
setHasOptionsMenu(false);
((MainActivity) requireActivity())
.setActionBarTitle(getResources().getString(R.string.navAccount));
myTypeface = AppUtil.getTypeface(ctx);
AccountContext account = ((BaseActivity) requireActivity()).getAccount();
if (account.getUserInfo() != null) {
viewData();
} else {
((MainActivity) requireActivity())
.setProfileInitListener(
(text) -> {
viewData();
});
}
return view;
}
public void viewData() {
TabLayout tabLayout = view.findViewById(R.id.tabs);
if (viewPager == null) {
viewPager = view.findViewById(R.id.accountSettingsContainer);
viewPager.setOffscreenPageLimit(1);
viewPager.setAdapter(new ViewPagerAdapter(this));
String[] tabTitles = {
ctx.getResources().getString(R.string.accountEmails),
ctx.getResources().getString(R.string.sshKeys)
};
new TabLayoutMediator(
tabLayout,
viewPager,
(tab, position) -> tab.setText(tabTitles[position]))
.attach();
ViewGroup viewGroup = (ViewGroup) tabLayout.getChildAt(0);
int tabsCount_ = viewGroup.getChildCount();
for (int j = 0; j < tabsCount_; j++) {
ViewGroup vgTab = (ViewGroup) viewGroup.getChildAt(j);
int tabChildCount = vgTab.getChildCount();
for (int i = 0; i < tabChildCount; i++) {
View tabViewChild = vgTab.getChildAt(i);
if (tabViewChild instanceof TextView) {
((TextView) tabViewChild).setTypeface(myTypeface);
}
}
}
}
}
public static class ViewPagerAdapter extends FragmentStateAdapter {
public ViewPagerAdapter(@NonNull Fragment fa) {
super(fa);
}
@NonNull @Override
public Fragment createFragment(int position) {
Fragment fragment = null;
switch (position) {
case 0: // Emails
return new AccountSettingsEmailsFragment();
case 1: // SSH keys
return new SSHKeysFragment();
}
assert false;
return fragment;
}
@Override
public int getItemCount() {
return 2;
}
}
}

View File

@ -1,102 +0,0 @@
package org.mian.gitnex.fragments;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ProgressBar;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import org.mian.gitnex.activities.MyProfileEmailActivity;
import org.mian.gitnex.adapters.MyProfileEmailsAdapter;
import org.mian.gitnex.databinding.FragmentProfileEmailsBinding;
import org.mian.gitnex.viewmodels.ProfileEmailsViewModel;
/**
* @author M M Arif
*/
public class MyProfileEmailsFragment extends Fragment {
public static boolean refreshEmails = false;
private ProfileEmailsViewModel profileEmailsViewModel;
private ProgressBar mProgressBar;
private MyProfileEmailsAdapter adapter;
private RecyclerView mRecyclerView;
private TextView noDataEmails;
public MyProfileEmailsFragment() {}
@Override
public View onCreateView(
@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
FragmentProfileEmailsBinding fragmentProfileEmailsBinding =
FragmentProfileEmailsBinding.inflate(inflater, container, false);
profileEmailsViewModel = new ViewModelProvider(this).get(ProfileEmailsViewModel.class);
final SwipeRefreshLayout swipeRefresh = fragmentProfileEmailsBinding.pullToRefresh;
noDataEmails = fragmentProfileEmailsBinding.noDataEmails;
mRecyclerView = fragmentProfileEmailsBinding.recyclerView;
mRecyclerView.setHasFixedSize(true);
mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
mProgressBar = fragmentProfileEmailsBinding.progressBar;
swipeRefresh.setOnRefreshListener(
() ->
new Handler(Looper.getMainLooper())
.postDelayed(
() -> {
swipeRefresh.setRefreshing(false);
profileEmailsViewModel.loadEmailsList(getContext());
},
200));
fetchDataAsync();
fragmentProfileEmailsBinding.addNewEmailAddress.setOnClickListener(
v1 -> startActivity(new Intent(getContext(), MyProfileEmailActivity.class)));
return fragmentProfileEmailsBinding.getRoot();
}
private void fetchDataAsync() {
profileEmailsViewModel
.getEmailsList(getContext())
.observe(
getViewLifecycleOwner(),
emailsListMain -> {
adapter = new MyProfileEmailsAdapter(getContext(), emailsListMain);
if (adapter.getItemCount() > 0) {
mRecyclerView.setAdapter(adapter);
noDataEmails.setVisibility(View.GONE);
} else {
adapter.notifyDataSetChanged();
mRecyclerView.setAdapter(adapter);
noDataEmails.setVisibility(View.VISIBLE);
}
mProgressBar.setVisibility(View.GONE);
});
}
@Override
public void onResume() {
super.onResume();
if (refreshEmails) {
profileEmailsViewModel.loadEmailsList(getContext());
refreshEmails = false;
}
}
}

View File

@ -1,155 +0,0 @@
package org.mian.gitnex.fragments;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.LinearLayoutManager;
import java.util.ArrayList;
import java.util.List;
import org.gitnex.tea4j.v2.models.User;
import org.mian.gitnex.R;
import org.mian.gitnex.adapters.UsersAdapter;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.databinding.FragmentProfileFollowersFollowingBinding;
import org.mian.gitnex.helpers.Constants;
import org.mian.gitnex.helpers.SnackBar;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
/**
* @author M M Arif
*/
public class MyProfileFollowersFragment extends Fragment {
private final String TAG = "MyProfileFollowersFragment";
private FragmentProfileFollowersFollowingBinding viewBinding;
private Context context;
private List<User> dataList;
private UsersAdapter adapter;
private int pageSize;
private int resultLimit;
@Override
public View onCreateView(
@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
viewBinding = FragmentProfileFollowersFollowingBinding.inflate(inflater, container, false);
context = getContext();
dataList = new ArrayList<>();
adapter = new UsersAdapter(dataList, context);
resultLimit = Constants.getCurrentResultLimit(context);
viewBinding.pullToRefresh.setOnRefreshListener(
() ->
new Handler(Looper.getMainLooper())
.postDelayed(
() -> {
viewBinding.pullToRefresh.setRefreshing(false);
loadInitial(resultLimit);
adapter.notifyDataChanged();
},
200));
adapter.setLoadMoreListener(
() ->
viewBinding.recyclerView.post(
() -> {
if (dataList.size() == resultLimit || pageSize == resultLimit) {
int page = (dataList.size() + resultLimit) / resultLimit;
loadMore(resultLimit, page);
}
}));
viewBinding.recyclerView.setHasFixedSize(true);
viewBinding.recyclerView.setLayoutManager(new LinearLayoutManager(context));
viewBinding.recyclerView.setAdapter(adapter);
loadInitial(resultLimit);
return viewBinding.getRoot();
}
private void loadInitial(int resultLimit) {
Call<List<User>> call =
RetrofitClient.getApiInterface(context).userCurrentListFollowers(1, resultLimit);
call.enqueue(
new Callback<List<User>>() {
@Override
public void onResponse(
@NonNull Call<List<User>> call,
@NonNull Response<List<User>> response) {
if (response.isSuccessful()) {
if (response.body() != null && response.body().size() > 0) {
dataList.clear();
dataList.addAll(response.body());
adapter.notifyDataChanged();
viewBinding.noData.setVisibility(View.GONE);
} else {
dataList.clear();
adapter.notifyDataChanged();
viewBinding.noData.setVisibility(View.VISIBLE);
}
viewBinding.progressBar.setVisibility(View.GONE);
} else if (response.code() == 404) {
viewBinding.noData.setVisibility(View.VISIBLE);
viewBinding.progressBar.setVisibility(View.GONE);
} else {
Log.e(TAG, String.valueOf(response.code()));
}
}
@Override
public void onFailure(@NonNull Call<List<User>> call, @NonNull Throwable t) {
Log.e(TAG, t.toString());
}
});
}
private void loadMore(int resultLimit, int page) {
viewBinding.progressBar.setVisibility(View.VISIBLE);
Call<List<User>> call =
RetrofitClient.getApiInterface(context).userCurrentListFollowers(page, resultLimit);
call.enqueue(
new Callback<List<User>>() {
@Override
public void onResponse(
@NonNull Call<List<User>> call,
@NonNull Response<List<User>> response) {
if (response.isSuccessful()) {
assert response.body() != null;
List<User> result = response.body();
if (result.size() > 0) {
pageSize = result.size();
dataList.addAll(result);
} else {
SnackBar.info(
context,
viewBinding.getRoot(),
getString(R.string.noMoreData));
adapter.setMoreDataAvailable(false);
}
adapter.notifyDataChanged();
viewBinding.progressBar.setVisibility(View.GONE);
} else {
Log.e(TAG, String.valueOf(response.code()));
}
}
@Override
public void onFailure(@NonNull Call<List<User>> call, @NonNull Throwable t) {
Log.e(TAG, t.toString());
}
});
}
}

View File

@ -1,157 +0,0 @@
package org.mian.gitnex.fragments;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.LinearLayoutManager;
import java.util.ArrayList;
import java.util.List;
import org.gitnex.tea4j.v2.models.User;
import org.mian.gitnex.R;
import org.mian.gitnex.adapters.UsersAdapter;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.databinding.FragmentProfileFollowersFollowingBinding;
import org.mian.gitnex.helpers.Constants;
import org.mian.gitnex.helpers.SnackBar;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
/**
* @author M M Arif
*/
public class MyProfileFollowingFragment extends Fragment {
private final String TAG = "MyProfileFollowingFragment";
private FragmentProfileFollowersFollowingBinding viewBinding;
private Context context;
private List<User> dataList;
private UsersAdapter adapter;
private int pageSize;
private int resultLimit;
@Override
public View onCreateView(
@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
viewBinding = FragmentProfileFollowersFollowingBinding.inflate(inflater, container, false);
context = getContext();
dataList = new ArrayList<>();
adapter = new UsersAdapter(dataList, context);
resultLimit = Constants.getCurrentResultLimit(context);
viewBinding.pullToRefresh.setOnRefreshListener(
() ->
new Handler(Looper.getMainLooper())
.postDelayed(
() -> {
viewBinding.pullToRefresh.setRefreshing(false);
loadInitial(resultLimit);
adapter.notifyDataChanged();
},
200));
adapter.setLoadMoreListener(
() ->
viewBinding.recyclerView.post(
() -> {
if (dataList.size() == resultLimit || pageSize == resultLimit) {
int page = (dataList.size() + resultLimit) / resultLimit;
loadMore(resultLimit, page);
}
}));
viewBinding.recyclerView.setHasFixedSize(true);
viewBinding.recyclerView.setLayoutManager(new LinearLayoutManager(context));
viewBinding.recyclerView.setAdapter(adapter);
loadInitial(resultLimit);
return viewBinding.getRoot();
}
private void loadInitial(int resultLimit) {
Call<List<User>> call =
RetrofitClient.getApiInterface(context).userCurrentListFollowing(1, resultLimit);
call.enqueue(
new Callback<List<User>>() {
@Override
public void onResponse(
@NonNull Call<List<User>> call,
@NonNull Response<List<User>> response) {
if (response.isSuccessful()) {
if (response.body() != null && response.body().size() > 0) {
dataList.clear();
dataList.addAll(response.body());
adapter.notifyDataChanged();
viewBinding.noData.setVisibility(View.GONE);
} else {
dataList.clear();
adapter.notifyDataChanged();
viewBinding.noData.setVisibility(View.VISIBLE);
}
viewBinding.progressBar.setVisibility(View.GONE);
} else if (response.code() == 404) {
viewBinding.noData.setVisibility(View.VISIBLE);
viewBinding.progressBar.setVisibility(View.GONE);
} else {
Log.e(TAG, String.valueOf(response.code()));
}
}
@Override
public void onFailure(@NonNull Call<List<User>> call, @NonNull Throwable t) {
Log.e(TAG, t.toString());
}
});
}
private void loadMore(int resultLimit, int page) {
viewBinding.progressBar.setVisibility(View.VISIBLE);
Call<List<User>> call =
RetrofitClient.getApiInterface(context).userCurrentListFollowing(page, resultLimit);
call.enqueue(
new Callback<List<User>>() {
@Override
public void onResponse(
@NonNull Call<List<User>> call,
@NonNull Response<List<User>> response) {
if (response.isSuccessful()) {
assert response.body() != null;
List<User> result = response.body();
if (result.size() > 0) {
pageSize = result.size();
dataList.addAll(result);
} else {
SnackBar.info(
context,
viewBinding.getRoot(),
getString(R.string.noMoreData));
adapter.setMoreDataAvailable(false);
}
adapter.notifyDataChanged();
viewBinding.progressBar.setVisibility(View.GONE);
} else {
Log.e(TAG, String.valueOf(response.code()));
}
}
@Override
public void onFailure(@NonNull Call<List<User>> call, @NonNull Throwable t) {
Log.e(TAG, t.toString());
}
});
}
}

View File

@ -1,177 +0,0 @@
package org.mian.gitnex.fragments;
import android.content.Context;
import android.graphics.Typeface;
import android.os.Bundle;
import android.text.Html;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentStatePagerAdapter;
import androidx.viewpager.widget.ViewPager;
import com.google.android.material.progressindicator.LinearProgressIndicator;
import com.google.android.material.tabs.TabLayout;
import java.util.Locale;
import org.mian.gitnex.R;
import org.mian.gitnex.activities.BaseActivity;
import org.mian.gitnex.activities.MainActivity;
import org.mian.gitnex.clients.PicassoService;
import org.mian.gitnex.helpers.AppUtil;
import org.mian.gitnex.helpers.RoundedTransformation;
import org.mian.gitnex.helpers.contexts.AccountContext;
/**
* @author M M Arif
*/
public class MyProfileFragment extends Fragment {
private Context ctx;
@Nullable @Override
public View onCreateView(
@NonNull LayoutInflater inflater,
@Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
ctx = getContext();
View v = inflater.inflate(R.layout.fragment_profile, container, false);
setHasOptionsMenu(false);
((MainActivity) requireActivity())
.setActionBarTitle(getResources().getString(R.string.navProfile));
AccountContext account = ((BaseActivity) requireActivity()).getAccount();
if (account.getUserInfo() != null) {
viewData(v, account);
} else {
// we have to wait until loading is finished
LinearProgressIndicator loading = v.findViewById(R.id.loadingIndicator);
loading.setVisibility(View.VISIBLE);
((MainActivity) requireActivity())
.setProfileInitListener(
(text) -> {
loading.setVisibility(View.GONE);
viewData(v, account);
});
}
return v;
}
public void viewData(View v, AccountContext account) {
TextView userFullName = v.findViewById(R.id.userFullName);
ImageView userAvatar = v.findViewById(R.id.userAvatar);
TextView userLogin = v.findViewById(R.id.userLogin);
TextView userLanguage = v.findViewById(R.id.userLanguage);
TextView userFollowersCount = v.findViewById(R.id.user_followers_count);
TextView userFollowingCount = v.findViewById(R.id.user_following_count);
TextView userStarredReposCount = v.findViewById(R.id.user_starred_repos_count);
String[] userLanguageCodes =
account.getUserInfo().getLanguage() != null
? account.getUserInfo().getLanguage().split("-")
: new String[] {""};
if (userLanguageCodes.length >= 2) {
Locale locale = new Locale(userLanguageCodes[0], userLanguageCodes[1]);
userLanguage.setText(locale.getDisplayLanguage());
} else {
userLanguage.setText(getResources().getConfiguration().locale.getDisplayLanguage());
}
userAvatar.setOnClickListener(
loginId ->
AppUtil.copyToClipboard(
ctx,
account.getAccount().getUserName(),
ctx.getString(
R.string.copyLoginIdToClipBoard,
account.getAccount().getUserName())));
userFullName.setText(Html.fromHtml(account.getFullName()));
userLogin.setText(getString(R.string.usernameWithAt, account.getAccount().getUserName()));
int avatarRadius = AppUtil.getPixelsFromDensity(ctx, 60);
PicassoService.getInstance(ctx)
.get()
.load(account.getUserInfo().getAvatarUrl())
.transform(new RoundedTransformation(avatarRadius, 0))
.placeholder(R.drawable.loader_animated)
.resize(120, 120)
.centerCrop()
.into(userAvatar);
userFollowersCount.setText(String.valueOf(account.getUserInfo().getFollowersCount()));
userFollowingCount.setText(String.valueOf(account.getUserInfo().getFollowingCount()));
userStarredReposCount.setText(String.valueOf(account.getUserInfo().getStarredReposCount()));
MyProfileFragment.SectionsPagerAdapter mSectionsPagerAdapter =
new SectionsPagerAdapter(getChildFragmentManager());
ViewPager mViewPager = v.findViewById(R.id.container);
mViewPager.setAdapter(mSectionsPagerAdapter);
Typeface myTypeface = AppUtil.getTypeface(requireContext());
TabLayout tabLayout = v.findViewById(R.id.tabs);
ViewGroup vg = (ViewGroup) tabLayout.getChildAt(0);
int tabsCount = vg.getChildCount();
for (int j = 0; j < tabsCount; j++) {
ViewGroup vgTab = (ViewGroup) vg.getChildAt(j);
int tabChildCount = vgTab.getChildCount();
for (int i = 0; i < tabChildCount; i++) {
View tabViewChild = vgTab.getChildAt(i);
if (tabViewChild instanceof TextView) {
((TextView) tabViewChild).setTypeface(myTypeface);
}
}
}
mViewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout));
tabLayout.addOnTabSelectedListener(
new TabLayout.ViewPagerOnTabSelectedListener(mViewPager));
}
public static class SectionsPagerAdapter extends FragmentStatePagerAdapter {
SectionsPagerAdapter(FragmentManager fm) {
super(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
}
@NonNull @Override
public Fragment getItem(int position) {
switch (position) {
case 0: // followers
return new MyProfileFollowersFragment();
case 1: // following
return new MyProfileFollowingFragment();
case 2: // emails
return new MyProfileEmailsFragment();
}
return null;
}
@Override
public int getCount() {
return 3;
}
}
}

View File

@ -0,0 +1,77 @@
package org.mian.gitnex.fragments;
import android.annotation.SuppressLint;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.LinearLayoutManager;
import org.mian.gitnex.adapters.SSHKeysAdapter;
import org.mian.gitnex.databinding.FragmentAccountSettingsSshKeysBinding;
import org.mian.gitnex.viewmodels.AccountSettingsSSHKeysViewModel;
/**
* @author M M Arif
*/
public class SSHKeysFragment extends Fragment {
private FragmentAccountSettingsSshKeysBinding viewBinding;
private Context context;
private SSHKeysAdapter adapter;
private AccountSettingsSSHKeysViewModel accountSettingsSSHKeysViewModel;
@Override
public View onCreateView(
@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
viewBinding = FragmentAccountSettingsSshKeysBinding.inflate(inflater, container, false);
context = getContext();
accountSettingsSSHKeysViewModel =
new ViewModelProvider(this).get(AccountSettingsSSHKeysViewModel.class);
viewBinding.recyclerView.setHasFixedSize(true);
viewBinding.recyclerView.setLayoutManager(new LinearLayoutManager(context));
viewBinding.pullToRefresh.setOnRefreshListener(
() ->
new Handler(Looper.getMainLooper())
.postDelayed(
() -> {
viewBinding.pullToRefresh.setRefreshing(false);
accountSettingsSSHKeysViewModel.loadKeysList(context);
},
200));
fetchDataAsync();
return viewBinding.getRoot();
}
@SuppressLint("NotifyDataSetChanged")
private void fetchDataAsync() {
accountSettingsSSHKeysViewModel
.getKeysList(context)
.observe(
getViewLifecycleOwner(),
keysListMain -> {
adapter = new SSHKeysAdapter(keysListMain);
if (adapter.getItemCount() > 0) {
viewBinding.recyclerView.setAdapter(adapter);
viewBinding.noData.setVisibility(View.GONE);
} else {
adapter.notifyDataSetChanged();
viewBinding.recyclerView.setAdapter(adapter);
viewBinding.noData.setVisibility(View.VISIBLE);
}
viewBinding.progressBar.setVisibility(View.GONE);
});
}
}

View File

@ -7,7 +7,10 @@ import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import java.io.IOException;
import java.util.Locale;
import okhttp3.ResponseBody;
import org.gitnex.tea4j.v2.models.Repository;
import org.gitnex.tea4j.v2.models.User;
import org.mian.gitnex.R;
import org.mian.gitnex.clients.PicassoService;
@ -16,6 +19,7 @@ import org.mian.gitnex.databinding.FragmentProfileDetailBinding;
import org.mian.gitnex.helpers.AlertDialogs;
import org.mian.gitnex.helpers.AppUtil;
import org.mian.gitnex.helpers.ClickListener;
import org.mian.gitnex.helpers.Markdown;
import org.mian.gitnex.helpers.RoundedTransformation;
import org.mian.gitnex.helpers.TimeHelper;
import org.mian.gitnex.helpers.TinyDB;
@ -63,6 +67,7 @@ public class DetailFragment extends Fragment {
locale = getResources().getConfiguration().locale;
getProfileDetail(username);
getProfileRepository(username);
return binding.getRoot();
}
@ -162,4 +167,133 @@ public class DetailFragment extends Fragment {
}
});
}
public void getProfileRepository(String username) {
Call<Repository> call =
RetrofitClient.getApiInterface(context).repoGet(username, ".profile");
call.enqueue(
new Callback<>() {
@Override
public void onResponse(
@NonNull Call<Repository> call,
@NonNull retrofit2.Response<Repository> response) {
if (response.isSuccessful() && response.body() != null) {
switch (response.code()) {
case 200:
String defBranch = response.body().getDefaultBranch();
binding.profileRepoView.setVisibility(View.VISIBLE);
Call<ResponseBody> call_profile =
RetrofitClient.getWebInterface(getContext())
.getFileContents(
username,
".profile",
defBranch,
"README.md");
call_profile.enqueue(
new Callback<>() {
@Override
public void onResponse(
@NonNull Call<ResponseBody> call_profile,
@NonNull retrofit2.Response<ResponseBody>
response) {
if (isAdded()) {
switch (response.code()) {
case 200:
assert response.body() != null;
new Thread(
() -> {
try {
Markdown
.render(
context,
response.body()
.string(),
binding.profileRepoContent);
} catch (
IOException
e) {
requireActivity()
.runOnUiThread(
() ->
Toasty
.error(
context,
context
.getString(
R
.string
.genericError)));
}
})
.start();
break;
case 401:
binding.profileRepoView
.setVisibility(View.GONE);
AlertDialogs
.authorizationTokenRevokedDialog(
context);
break;
case 403:
binding.profileRepoView
.setVisibility(View.GONE);
Toasty.error(
context,
context.getString(
R.string
.authorizeError));
break;
default:
break;
}
}
}
@Override
public void onFailure(
@NonNull Call<ResponseBody> call_profile,
@NonNull Throwable t) {}
});
break;
case 401:
AlertDialogs.authorizationTokenRevokedDialog(context);
binding.profileRepoView.setVisibility(View.GONE);
break;
case 403:
binding.profileRepoView.setVisibility(View.GONE);
Toasty.error(
context, context.getString(R.string.authorizeError));
break;
default:
binding.profileRepoView.setVisibility(View.GONE);
Toasty.error(context, getString(R.string.genericError));
break;
}
}
binding.progressBar.setVisibility(View.GONE);
}
@Override
public void onFailure(@NonNull Call<Repository> call, @NonNull Throwable t) {
binding.profileRepoView.setVisibility(View.GONE);
}
});
}
}

View File

@ -17,7 +17,7 @@ import retrofit2.Response;
/**
* @author M M Arif
*/
public class ProfileEmailsViewModel extends ViewModel {
public class AccountSettingsEmailsViewModel extends ViewModel {
private MutableLiveData<List<Email>> emailsList;

View File

@ -0,0 +1,63 @@
package org.mian.gitnex.viewmodels;
import android.content.Context;
import androidx.annotation.NonNull;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
import java.util.List;
import org.gitnex.tea4j.v2.models.PublicKey;
import org.mian.gitnex.R;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.helpers.Constants;
import org.mian.gitnex.helpers.Toasty;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
/**
* @author M M Arif
*/
public class AccountSettingsSSHKeysViewModel extends ViewModel {
private MutableLiveData<List<PublicKey>> keysList;
private int resultLimit;
public LiveData<List<PublicKey>> getKeysList(Context ctx) {
keysList = new MutableLiveData<>();
resultLimit = Constants.getCurrentResultLimit(ctx);
loadKeysList(ctx);
return keysList;
}
public void loadKeysList(Context ctx) {
Call<List<PublicKey>> call =
RetrofitClient.getApiInterface(ctx).userCurrentListKeys("", 1, resultLimit);
call.enqueue(
new Callback<>() {
@Override
public void onResponse(
@NonNull Call<List<PublicKey>> call,
@NonNull Response<List<PublicKey>> response) {
if (response.isSuccessful()) {
keysList.postValue(response.body());
} else {
Toasty.error(ctx, ctx.getString(R.string.genericError));
}
}
@Override
public void onFailure(
@NonNull Call<List<PublicKey>> call, @NonNull Throwable t) {
Toasty.error(ctx, ctx.getString(R.string.genericServerResponseError));
}
});
}
}

View File

@ -0,0 +1,34 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M20,7h-9"
android:strokeLineJoin="round"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="?attr/iconsColor"
android:strokeLineCap="round"/>
<path
android:pathData="M14,17H5"
android:strokeLineJoin="round"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="?attr/iconsColor"
android:strokeLineCap="round"/>
<path
android:pathData="M17,17m-3,0a3,3 0,1 1,6 0a3,3 0,1 1,-6 0"
android:strokeLineJoin="round"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="?attr/iconsColor"
android:strokeLineCap="round"/>
<path
android:pathData="M7,7m-3,0a3,3 0,1 1,6 0a3,3 0,1 1,-6 0"
android:strokeLineJoin="round"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="?attr/iconsColor"
android:strokeLineCap="round"/>
</vector>

View File

@ -60,7 +60,7 @@
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dimen8dp"
android:layout_marginBottom="@dimen/dimen8dp"
android:hint="@string/profileEmailTitle"
android:hint="@string/accountEmailTitle"
android:textColorHint="?attr/hintColor"
app:boxBackgroundColor="?attr/inputBackgroundColor"
app:boxStrokeErrorColor="@color/darkRed"

View File

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/primaryBackgroundColor"
android:orientation="vertical">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/Widget.AppCompat.SearchView"
app:elevation="@dimen/dimen0dp">
<com.google.android.material.tabs.TabLayout
android:id="@+id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/primaryBackgroundColor"
app:tabIndicatorColor="?attr/pagerTabIndicatorColor"
app:tabMode="fixed"
app:tabTextAppearance="@style/customTabLayout"
app:tabTextColor="?attr/primaryTextColor">
</com.google.android.material.tabs.TabLayout>
</com.google.android.material.appbar.AppBarLayout>
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/accountSettingsContainer"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"/>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="@dimen/dimen8dp">
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/pullToRefresh"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:paddingBottom="@dimen/dimen72dp" />
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
</FrameLayout>
<com.google.android.material.progressindicator.LinearProgressIndicator
android:id="@+id/progress_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:indeterminate="true"
style="@style/Widget.Material3.LinearProgressIndicator"
app:indicatorColor="?attr/progressIndicatorColor" />
<TextView
android:id="@+id/no_data"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="@dimen/dimen16dp"
android:gravity="center"
android:text="@string/noDataFound"
android:textColor="?attr/primaryTextColor"
android:textSize="@dimen/dimen20sp"
android:visibility="gone" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@ -1,273 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.google.android.material.progressindicator.LinearProgressIndicator
android:id="@+id/loadingIndicator"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:indeterminate="true"
android:visibility="gone" />
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/AppTheme.AppBarOverlay"
android:background="?attr/primaryBackgroundColor"
app:elevation="@dimen/dimen0dp">
<com.google.android.material.card.MaterialCardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="?attr/materialCardViewFilledStyle"
android:layout_marginStart="@dimen/dimen8dp"
android:layout_marginEnd="@dimen/dimen8dp"
android:layout_marginBottom="@dimen/dimen12dp"
app:cardElevation="@dimen/dimen0dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:foreground="?android:attr/selectableItemBackground"
android:background="?attr/materialCardBackgroundColor"
android:padding="@dimen/dimen24dp"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
tools:ignore="UseCompoundDrawables">
<com.google.android.material.card.MaterialCardView
android:layout_width="@dimen/dimen80dp"
android:layout_height="@dimen/dimen80dp"
style="?attr/materialCardViewFilledStyle"
android:layout_marginBottom="@dimen/dimen8dp"
app:cardElevation="@dimen/dimen0dp"
app:cardCornerRadius="@dimen/dimen40dp">
<ImageView
android:id="@+id/userAvatar"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:contentDescription="@string/generalImgContentText"
android:src="@mipmap/app_logo_round" />
</com.google.android.material.card.MaterialCardView>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="@dimen/dimen24dp"
android:paddingEnd="@dimen/dimen10dp"
android:orientation="vertical">
<TextView
android:id="@+id/userFullName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="?attr/primaryTextColor"
android:textIsSelectable="true"
android:textSize="@dimen/dimen18sp" />
<TextView
android:id="@+id/userLogin"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/dimen10dp"
android:textColor="?attr/primaryTextColor"
android:textIsSelectable="true"
android:textSize="@dimen/dimen14sp" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_vertical"
tools:ignore="UseCompoundDrawables">
<ImageView
android:id="@+id/userLanguageIcon"
android:layout_width="@dimen/dimen16dp"
android:layout_height="@dimen/dimen16dp"
android:layout_marginEnd="@dimen/dimen4dp"
android:contentDescription="@string/generalImgContentText"
android:src="@drawable/ic_language"
app:tint="?attr/iconsColor" />
<TextView
android:id="@+id/userLanguage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="?attr/primaryTextColor"
android:textIsSelectable="true"
android:textSize="@dimen/dimen14sp" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dimen20dp"
android:layout_marginBottom="@dimen/dimen0dp"
android:orientation="horizontal"
android:baselineAligned="false">
<LinearLayout
android:id="@+id/followers_section"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="?attr/primaryTextColor"
android:text="@string/profileTabFollowers"
android:textSize="@dimen/dimen14sp" />
<TextView
android:id="@+id/user_followers_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="?attr/primaryTextColor"
android:paddingTop="@dimen/dimen6dp"
android:textStyle="bold"
android:textSize="@dimen/dimen14sp" />
</LinearLayout>
<LinearLayout
android:id="@+id/following_section"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="?attr/primaryTextColor"
android:text="@string/profileTabFollowing"
android:textSize="@dimen/dimen14sp" />
<TextView
android:id="@+id/user_following_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="?attr/primaryTextColor"
android:paddingTop="@dimen/dimen6dp"
android:textStyle="bold"
android:textSize="@dimen/dimen14sp" />
</LinearLayout>
<LinearLayout
android:id="@+id/starred_repos_section"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="?attr/primaryTextColor"
android:text="@string/starredRepos"
android:textSize="@dimen/dimen14sp" />
<TextView
android:id="@+id/user_starred_repos_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="?attr/primaryTextColor"
android:paddingTop="@dimen/dimen6dp"
android:textStyle="bold"
android:textSize="@dimen/dimen14sp" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
</com.google.android.material.appbar.AppBarLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/primaryBackgroundColor"
android:layout_marginTop="@dimen/dimen200dp"
android:orientation="vertical">
<com.google.android.material.card.MaterialCardView
android:id="@+id/fragmentProfileCard"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="@dimen/dimen8dp"
app:strokeWidth="@dimen/dimen2dp"
app:cardCornerRadius="@dimen/dimen10dp"
app:strokeColor="?attr/colorPrimary"
style="?attr/materialCardViewFilledStyle">
<com.google.android.material.tabs.TabLayout
android:id="@+id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabTextAppearance="@android:style/TextAppearance.Material.Widget.TabWidget"
app:tabIndicatorGravity="stretch"
app:tabMode="fixed"
app:tabIndicatorColor="?attr/colorPrimary"
app:tabIndicatorFullWidth="true"
android:background="?attr/primaryBackgroundColor"
app:tabSelectedTextColor="@android:color/white"
app:tabTextColor="?attr/colorPrimary">
<com.google.android.material.tabs.TabItem
android:id="@+id/profileTabFollowers"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/profileTabFollowers" />
<com.google.android.material.tabs.TabItem
android:id="@+id/profileTabFollowing"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/profileTabFollowing" />
<com.google.android.material.tabs.TabItem
android:id="@+id/profileTabEmails"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/profileTabEmails" />
</com.google.android.material.tabs.TabLayout>
</com.google.android.material.card.MaterialCardView>
</LinearLayout>
<androidx.viewpager.widget.ViewPager
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dimen48dp"
android:background="?attr/primaryBackgroundColor"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@ -17,276 +17,330 @@
style="@style/Widget.Material3.LinearProgressIndicator"
app:indicatorColor="?attr/progressIndicatorColor" />
<com.google.android.material.card.MaterialCardView
<androidx.core.widget.NestedScrollView
android:orientation="vertical"
android:background="?attr/primaryBackgroundColor"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="?attr/materialCardViewFilledStyle"
android:layout_margin="@dimen/dimen8dp"
app:cardElevation="@dimen/dimen0dp">
android:layout_height="match_parent">
<LinearLayout
android:padding="@dimen/dimen8dp"
android:orientation="vertical"
android:id="@+id/repoInfoLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:foreground="?android:attr/selectableItemBackground"
android:background="?attr/materialCardBackgroundColor"
android:padding="@dimen/dimen24dp"
android:orientation="vertical">
android:layout_height="wrap_content">
<LinearLayout
<com.google.android.material.card.MaterialCardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
tools:ignore="UseCompoundDrawables">
<com.google.android.material.card.MaterialCardView
android:layout_width="@dimen/dimen80dp"
android:layout_height="@dimen/dimen80dp"
style="?attr/materialCardViewFilledStyle"
android:layout_marginBottom="@dimen/dimen8dp"
app:cardElevation="@dimen/dimen0dp"
app:cardCornerRadius="@dimen/dimen40dp">
<ImageView
android:id="@+id/userAvatar"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:contentDescription="@string/generalImgContentText"
android:src="@mipmap/app_logo_round" />
</com.google.android.material.card.MaterialCardView>
style="?attr/materialCardViewFilledStyle"
app:cardElevation="@dimen/dimen0dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="@dimen/dimen24dp"
android:paddingEnd="@dimen/dimen10dp"
android:foreground="?android:attr/selectableItemBackground"
android:background="?attr/materialCardBackgroundColor"
android:padding="@dimen/dimen24dp"
android:orientation="vertical">
<TextView
android:id="@+id/userFullName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="?attr/primaryTextColor"
android:textIsSelectable="true"
android:textSize="@dimen/dimen18sp" />
<TextView
android:id="@+id/userLogin"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/dimen10dp"
android:textColor="?attr/primaryTextColor"
android:textIsSelectable="true"
android:textSize="@dimen/dimen14sp" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dimen20dp"
android:layout_marginBottom="@dimen/dimen0dp"
android:orientation="horizontal"
android:baselineAligned="false">
<LinearLayout
android:id="@+id/followers_section"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="?attr/primaryTextColor"
android:text="@string/profileTabFollowers"
android:textSize="@dimen/dimen14sp" />
<TextView
android:id="@+id/user_followers_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="?attr/primaryTextColor"
android:paddingTop="@dimen/dimen6dp"
android:textStyle="bold"
android:textSize="@dimen/dimen14sp" />
</LinearLayout>
<LinearLayout
android:id="@+id/following_section"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="?attr/primaryTextColor"
android:text="@string/profileTabFollowing"
android:textSize="@dimen/dimen14sp" />
<TextView
android:id="@+id/user_following_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="?attr/primaryTextColor"
android:paddingTop="@dimen/dimen6dp"
android:textStyle="bold"
android:textSize="@dimen/dimen14sp" />
</LinearLayout>
<LinearLayout
android:id="@+id/starred_repos_section"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="?attr/primaryTextColor"
android:text="@string/starredRepos"
android:textSize="@dimen/dimen14sp" />
<TextView
android:id="@+id/user_starred_repos_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="?attr/primaryTextColor"
android:paddingTop="@dimen/dimen6dp"
android:textStyle="bold"
android:textSize="@dimen/dimen14sp" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dimen32dp"
android:orientation="horizontal">
<ImageView
android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/generalImgContentText"
app:srcCompat="@drawable/ic_email" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/dimen16dp"
android:gravity="center_vertical"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/userEmail"
android:textColor="?attr/primaryTextColor"
android:textSize="@dimen/dimen16sp" />
<TextView
android:id="@+id/userEmail"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:alpha="0.9"
android:textColor="?attr/primaryTextColor"
android:textSize="@dimen/dimen14sp" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dimen32dp"
android:orientation="horizontal">
<ImageView
android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/generalImgContentText"
app:srcCompat="@drawable/ic_language"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/dimen16dp"
android:gravity="center_vertical"
android:orientation="vertical">
android:orientation="horizontal"
tools:ignore="UseCompoundDrawables">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/settingsLanguageSelectorHeader"
android:textColor="?attr/primaryTextColor"
android:textSize="@dimen/dimen16sp" />
<com.google.android.material.card.MaterialCardView
android:layout_width="@dimen/dimen80dp"
android:layout_height="@dimen/dimen80dp"
style="?attr/materialCardViewFilledStyle"
android:layout_marginBottom="@dimen/dimen8dp"
app:cardElevation="@dimen/dimen0dp"
app:cardCornerRadius="@dimen/dimen40dp">
<TextView
android:id="@+id/userLang"
<ImageView
android:id="@+id/userAvatar"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:contentDescription="@string/generalImgContentText"
android:src="@mipmap/app_logo_round" />
</com.google.android.material.card.MaterialCardView>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:alpha="0.9"
android:textColor="?attr/primaryTextColor"
android:textSize="@dimen/dimen14sp" />
android:paddingStart="@dimen/dimen24dp"
android:paddingEnd="@dimen/dimen10dp"
android:orientation="vertical">
<TextView
android:id="@+id/userFullName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="?attr/primaryTextColor"
android:textIsSelectable="true"
android:textSize="@dimen/dimen18sp" />
<TextView
android:id="@+id/userLogin"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/dimen10dp"
android:textColor="?attr/primaryTextColor"
android:textIsSelectable="true"
android:textSize="@dimen/dimen14sp" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dimen32dp"
android:orientation="horizontal">
<ImageView
android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/generalImgContentText"
app:srcCompat="@drawable/ic_calendar"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/dimen16dp"
android:gravity="center_vertical"
android:orientation="vertical">
android:layout_marginTop="@dimen/dimen20dp"
android:layout_marginBottom="@dimen/dimen0dp"
android:orientation="horizontal"
android:baselineAligned="false">
<TextView
<LinearLayout
android:id="@+id/followers_section"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/joined"
android:textColor="?attr/primaryTextColor"
android:textSize="@dimen/dimen16sp" />
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical">
<TextView
android:id="@+id/userJoinedOn"
android:layout_width="match_parent"
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="?attr/primaryTextColor"
android:text="@string/profileTabFollowers"
android:textSize="@dimen/dimen14sp" />
<TextView
android:id="@+id/user_followers_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="?attr/primaryTextColor"
android:paddingTop="@dimen/dimen6dp"
android:textStyle="bold"
android:textSize="@dimen/dimen14sp" />
</LinearLayout>
<LinearLayout
android:id="@+id/following_section"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:alpha="0.9"
android:textColor="?attr/primaryTextColor"
android:textSize="@dimen/dimen14sp" />
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="?attr/primaryTextColor"
android:text="@string/profileTabFollowing"
android:textSize="@dimen/dimen14sp" />
<TextView
android:id="@+id/user_following_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="?attr/primaryTextColor"
android:paddingTop="@dimen/dimen6dp"
android:textStyle="bold"
android:textSize="@dimen/dimen14sp" />
</LinearLayout>
<LinearLayout
android:id="@+id/starred_repos_section"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="?attr/primaryTextColor"
android:text="@string/starredRepos"
android:textSize="@dimen/dimen14sp" />
<TextView
android:id="@+id/user_starred_repos_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="?attr/primaryTextColor"
android:paddingTop="@dimen/dimen6dp"
android:textStyle="bold"
android:textSize="@dimen/dimen14sp" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dimen32dp"
android:orientation="horizontal">
<ImageView
android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/generalImgContentText"
app:srcCompat="@drawable/ic_email" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/dimen16dp"
android:gravity="center_vertical"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/userEmail"
android:textColor="?attr/primaryTextColor"
android:textSize="@dimen/dimen16sp" />
<TextView
android:id="@+id/userEmail"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:alpha="0.9"
android:textColor="?attr/primaryTextColor"
android:textSize="@dimen/dimen14sp" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dimen32dp"
android:orientation="horizontal">
<ImageView
android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/generalImgContentText"
app:srcCompat="@drawable/ic_language"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/dimen16dp"
android:gravity="center_vertical"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/settingsLanguageSelectorHeader"
android:textColor="?attr/primaryTextColor"
android:textSize="@dimen/dimen16sp" />
<TextView
android:id="@+id/userLang"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:alpha="0.9"
android:textColor="?attr/primaryTextColor"
android:textSize="@dimen/dimen14sp" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dimen32dp"
android:orientation="horizontal">
<ImageView
android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/generalImgContentText"
app:srcCompat="@drawable/ic_calendar"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/dimen16dp"
android:gravity="center_vertical"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/joined"
android:textColor="?attr/primaryTextColor"
android:textSize="@dimen/dimen16sp" />
<TextView
android:id="@+id/userJoinedOn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:alpha="0.9"
android:textColor="?attr/primaryTextColor"
android:textSize="@dimen/dimen14sp" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
<com.google.android.material.card.MaterialCardView
android:id="@+id/profile_repo_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="?attr/materialCardViewFilledStyle"
app:cardElevation="@dimen/dimen0dp"
android:layout_marginTop="@dimen/dimen8dp"
android:visibility="gone">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:foreground="?android:attr/selectableItemBackground"
android:background="?attr/materialCardBackgroundColor"
android:padding="@dimen/dimen24dp"
android:orientation="vertical">
<TextView
android:id="@+id/profile_repo_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textIsSelectable="true"
android:textSize="@dimen/dimen16sp"
android:textColor="?attr/primaryTextColor" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/profile_repo_content1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textIsSelectable="true"
android:textSize="@dimen/dimen16sp"
android:visibility="gone"
android:textColor="?attr/primaryTextColor" />
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
</androidx.core.widget.NestedScrollView>
</LinearLayout>

View File

@ -28,7 +28,7 @@
android:id="@+id/userEmail"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/profileEmailTitle"
android:text="@string/accountEmailTitle"
android:textColor="?attr/primaryTextColor"
android:textSize="@dimen/dimen16sp"/>

View File

@ -0,0 +1,50 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingTop="@dimen/dimen4dp"
android:paddingBottom="@dimen/dimen4dp"
tools:ignore="UseCompoundDrawables">
<com.google.android.material.card.MaterialCardView
android:id="@+id/card"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:cardBackgroundColor="?attr/primaryBackgroundColor"
style="?attr/materialCardViewFilledStyle">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/materialCardBackgroundColor"
android:padding="@dimen/dimen12dp"
android:orientation="vertical">
<TextView
android:id="@+id/keyName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/sshKeys"
android:textColor="?attr/primaryTextColor"
android:textIsSelectable="true"
android:textSize="@dimen/dimen16sp" />
<TextView
android:id="@+id/key"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/sshKeys"
android:layout_marginTop="@dimen/dimen8dp"
android:textColor="?attr/primaryTextColor"
android:textIsSelectable="true"
android:textSize="@dimen/dimen12sp" />
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
</LinearLayout>

View File

@ -60,6 +60,10 @@
android:icon="@drawable/ic_person"
android:title="@string/navProfile"/>
<item android:id="@+id/nav_account_settings"
android:icon="@drawable/ic_account_settings"
android:title="@string/navAccount" />
<item android:id="@+id/nav_administration"
android:icon="@drawable/ic_tool"
android:title="@string/navAdministration"

View File

@ -69,7 +69,7 @@
<item>@string/pageTitleStarredRepos</item>
<item>@string/navOrg</item>
<item>@string/navRepos</item>
<item>@string/navProfile</item>
<item>@string/navAccount</item>
<item>@string/pageTitleExplore</item>
<item>@string/titleDrafts</item>
<item>@string/pageTitleNotifications</item>

View File

@ -35,6 +35,7 @@
<string name="navMyIssues">My Issues</string>
<string name="navMostVisited">Most Visited Repos</string>
<string name="navNotes">Notes</string>
<string name="navAccount">Account Settings</string>
<!-- menu items -->
<!-- page titles -->
@ -342,16 +343,19 @@
<!-- profile section -->
<string name="profileTabFollowers">Followers</string>
<string name="profileTabFollowing">Following</string>
<string name="profileCreateNewEmailAddress">Add Email Address</string>
<string name="profileEmailTitle">Email Address</string>
<string name="usernameWithAt" translatable="false">\u0040%1$s</string>
<!-- profile section -->
<!-- account settings -->
<string name="accountEmails">Emails</string>
<string name="accountEmailTitle">Email Address</string>
<string name="emailAddedText">New email added successfully</string>
<string name="emailErrorEmpty">Email address is empty</string>
<string name="emailErrorInvalid">Email address is not valid</string>
<string name="emailErrorInUse">Email address is already in use</string>
<string name="emailTypeText">Primary</string>
<string name="profileTabEmails">Emails</string>
<string name="usernameWithAt" translatable="false">\u0040%1$s</string>
<!-- profile section -->
<string name="sshKeys">SSH Keys</string>
<!-- account settings -->
<!-- single issue section -->
<string name="singleIssueEditLabels">Add / Remove Labels</string>