diff --git a/app/src/main/java/org/nuclearfog/twidda/backend/utils/AppStyles.java b/app/src/main/java/org/nuclearfog/twidda/backend/utils/AppStyles.java index b0b7b875..4226411d 100644 --- a/app/src/main/java/org/nuclearfog/twidda/backend/utils/AppStyles.java +++ b/app/src/main/java/org/nuclearfog/twidda/backend/utils/AppStyles.java @@ -37,6 +37,8 @@ import androidx.core.content.res.ResourcesCompat; import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; import androidx.viewpager2.widget.ViewPager2; +import com.google.android.material.floatingactionbutton.FloatingActionButton; +import com.google.android.material.navigation.NavigationView; import com.kyleduo.switchbutton.SwitchButton; import org.nuclearfog.twidda.BuildConfig; @@ -362,6 +364,10 @@ public class AppStyles { int[] thumbColor = {settings.getIconColor()}; sw.setTintColor(settings.getHighlightColor()); sw.setThumbColor(new ColorStateList(SWITCH_STATES, thumbColor)); + } else if (child instanceof FloatingActionButton) { + FloatingActionButton floatingButton = (FloatingActionButton) child; + floatingButton.setBackgroundTintList(ColorStateList.valueOf(settings.getHighlightColor())); + setDrawableColor(floatingButton, settings.getIconColor()); } else if (child instanceof SeekBar) { SeekBar seekBar = (SeekBar) child; setSeekBarColor(seekBar, settings); @@ -393,6 +399,9 @@ public class AppStyles { CardView card = (CardView) child; card.setCardBackgroundColor(settings.getCardColor()); setSubViewTheme(card, color); + } else if (child instanceof NavigationView) { + child.setBackgroundColor(settings.getBackgroundColor()); + setSubViewTheme((ViewGroup) child, color); } else if (!(child instanceof ViewPager2)) { setSubViewTheme((ViewGroup) child, color); } diff --git a/app/src/main/java/org/nuclearfog/twidda/ui/activities/MainActivity.java b/app/src/main/java/org/nuclearfog/twidda/ui/activities/MainActivity.java index 89e8027d..d8423a58 100644 --- a/app/src/main/java/org/nuclearfog/twidda/ui/activities/MainActivity.java +++ b/app/src/main/java/org/nuclearfog/twidda/ui/activities/MainActivity.java @@ -4,10 +4,18 @@ import android.app.Dialog; import android.content.Context; import android.content.Intent; import android.graphics.Color; +import android.graphics.drawable.ColorDrawable; +import android.graphics.drawable.Drawable; import android.os.Bundle; +import android.text.Spannable; +import android.text.SpannableString; import android.view.Menu; import android.view.MenuItem; +import android.view.View; +import android.view.View.OnClickListener; import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; import android.widget.Toast; import androidx.activity.result.ActivityResult; @@ -20,11 +28,24 @@ import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.widget.SearchView; import androidx.appcompat.widget.SearchView.OnQueryTextListener; import androidx.appcompat.widget.Toolbar; +import androidx.drawerlayout.widget.DrawerLayout; import androidx.viewpager2.widget.ViewPager2; +import com.google.android.material.navigation.NavigationView; +import com.google.android.material.navigation.NavigationView.OnNavigationItemSelectedListener; +import com.squareup.picasso.Picasso; + import org.nuclearfog.twidda.R; +import org.nuclearfog.twidda.backend.async.AsyncExecutor; +import org.nuclearfog.twidda.backend.async.UserLoader; +import org.nuclearfog.twidda.backend.async.UserLoader.UserParam; +import org.nuclearfog.twidda.backend.async.UserLoader.UserResult; +import org.nuclearfog.twidda.backend.image.PicassoBuilder; import org.nuclearfog.twidda.backend.utils.AppStyles; +import org.nuclearfog.twidda.backend.utils.EmojiUtils; +import org.nuclearfog.twidda.backend.utils.StringUtils; import org.nuclearfog.twidda.config.GlobalSettings; +import org.nuclearfog.twidda.model.User; import org.nuclearfog.twidda.ui.adapter.viewpager.HomeAdapter; import org.nuclearfog.twidda.ui.dialogs.ProgressDialog; import org.nuclearfog.twidda.ui.views.TabSelector; @@ -35,10 +56,16 @@ import org.nuclearfog.twidda.ui.views.TabSelector.OnTabSelectedListener; * * @author nuclearfog */ -public class MainActivity extends AppCompatActivity implements ActivityResultCallback, OnTabSelectedListener, OnQueryTextListener { +public class MainActivity extends AppCompatActivity implements ActivityResultCallback, OnTabSelectedListener, + OnQueryTextListener, OnNavigationItemSelectedListener, OnClickListener, AsyncExecutor.AsyncCallback { public static final String KEY_SELECT_NOTIFICATION = "main_notification"; + /** + * color of the profile image placeholder + */ + private static final int IMAGE_PLACEHOLDER_COLOR = 0x2F000000; + private ActivityResultLauncher activityResultLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), this); @Nullable @@ -46,12 +73,20 @@ public class MainActivity extends AppCompatActivity implements ActivityResultCal @Nullable private HomeAdapter adapter; private GlobalSettings settings; + private UserLoader userLoader; + private Picasso picasso; private Dialog loadingCircle; + + private DrawerLayout drawerLayout; private TabSelector tabSelector; private ViewPager2 viewPager; - private Toolbar toolbar; - private ViewGroup root; + private ImageView profileImage; + private TextView username, screenname; + private TextView followingCount, followerCount; + + @Nullable + private User currentUser; @Override @@ -64,22 +99,47 @@ public class MainActivity extends AppCompatActivity implements ActivityResultCal protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.page_main); - toolbar = findViewById(R.id.home_toolbar); + NavigationView navigationView = findViewById(R.id.home_navigator); + ViewGroup header = (ViewGroup) navigationView.getHeaderView(0); + Toolbar toolbar = findViewById(R.id.home_toolbar); + View floatingButton = findViewById(R.id.home_post); + drawerLayout = findViewById(R.id.main_layout); viewPager = findViewById(R.id.home_pager); tabSelector = findViewById(R.id.home_tab); - root = findViewById(R.id.main_layout); - loadingCircle = new ProgressDialog(this, null); + profileImage = header.findViewById(R.id.navigation_profile_image); + username = header.findViewById(R.id.navigation_profile_username); + screenname = header.findViewById(R.id.navigation_profile_screenname); + followerCount = header.findViewById(R.id.navigation_profile_follower); + followingCount = header.findViewById(R.id.navigation_profile_following); + userLoader = new UserLoader(this); + loadingCircle = new ProgressDialog(this, null); settings = GlobalSettings.get(this); + picasso = PicassoBuilder.get(this); tabSelector.addViewPager(viewPager); viewPager.setOffscreenPageLimit(4); - AppStyles.setTheme(root); - AppStyles.setOverflowIcon(toolbar, settings.getIconColor()); - toolbar.setTitle(""); + toolbar.setNavigationIcon(R.drawable.menu); setSupportActionBar(toolbar); + AppStyles.setTheme(header); + navigationView.post(new Runnable() { + @Override + public void run() { + AppStyles.setTheme(navigationView); + } + }); + + toolbar.setNavigationOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + drawerLayout.open(); + } + }); tabSelector.addOnTabSelectedListener(this); + navigationView.setNavigationItemSelectedListener(this); + floatingButton.setOnClickListener(this); + header.setOnClickListener(this); } @@ -92,13 +152,33 @@ public class MainActivity extends AppCompatActivity implements ActivityResultCal activityResultLauncher.launch(loginIntent); } // initialize lists - else if (adapter == null) { - adapter = new HomeAdapter(this); - viewPager.setAdapter(adapter); - setStyle(); - if (getIntent().getBooleanExtra(KEY_SELECT_NOTIFICATION, false)) { - // select notification page if user clicks on notification - viewPager.setCurrentItem(adapter.getItemCount() - 1, false); + else { + if (adapter == null) { + adapter = new HomeAdapter(this); + viewPager.setAdapter(adapter); + setStyle(); + if (getIntent().getBooleanExtra(KEY_SELECT_NOTIFICATION, false)) { + // select notification page if user clicks on notification + viewPager.setCurrentItem(adapter.getItemCount() - 1, false); + } + } + if (currentUser == null) { + UserParam param = new UserParam(UserParam.DATABASE, settings.getLogin().getId()); + userLoader.execute(param, this); + } + } + } + + + @Override + public void onBackPressed() { + if (viewPager.getCurrentItem() > 0) { + viewPager.setCurrentItem(0); + } else { + if (drawerLayout.isOpen()) { + drawerLayout.close(); + } else { + super.onBackPressed(); } } } @@ -115,12 +195,22 @@ public class MainActivity extends AppCompatActivity implements ActivityResultCal public void onActivityResult(ActivityResult result) { invalidateMenu(); switch (result.getResultCode()) { + case ProfileActivity.RETURN_USER_UPDATED: + if (result.getData() != null) { + Object object = result.getData().getSerializableExtra(ProfileActivity.KEY_USER); + if (object instanceof User) { + setCurrentUser((User) object); + } + } + break; + case LoginActivity.RETURN_LOGIN_CANCELED: finish(); break; case SettingsActivity.RETURN_APP_LOGOUT: viewPager.setAdapter(null); + setCurrentUser(null); adapter = null; break; @@ -139,6 +229,7 @@ public class MainActivity extends AppCompatActivity implements ActivityResultCal if (adapter != null) adapter.notifySettingsChanged(); setStyle(); + setCurrentUser(currentUser); break; } } @@ -149,9 +240,7 @@ public class MainActivity extends AppCompatActivity implements ActivityResultCal getMenuInflater().inflate(R.menu.home, menu); AppStyles.setMenuIconColor(menu, settings.getIconColor()); MenuItem search = menu.findItem(R.id.menu_search); - MenuItem filter = menu.findItem(R.id.menu_filter); SearchView searchView = (SearchView) search.getActionView(); - filter.setVisible(settings.getLogin().getConfiguration().isFilterSupported()); searchView.setOnQueryTextListener(this); return true; } @@ -159,9 +248,7 @@ public class MainActivity extends AppCompatActivity implements ActivityResultCal @Override public boolean onPrepareOptionsMenu(Menu menu) { - MenuItem message = menu.findItem(R.id.menu_message); MenuItem search = menu.findItem(R.id.menu_search); - message.setVisible(settings.getLogin().getConfiguration().directmessageSupported()); search.collapseActionView(); return true; } @@ -169,60 +256,49 @@ public class MainActivity extends AppCompatActivity implements ActivityResultCal @Override public boolean onOptionsItemSelected(@NonNull MenuItem item) { - // open home profile - if (item.getItemId() == R.id.menu_profile) { - Intent intent = new Intent(this, ProfileActivity.class); - intent.putExtra(ProfileActivity.KEY_ID, settings.getLogin().getId()); - startActivity(intent); - return true; - } - // open filter page - else if (item.getItemId() == R.id.menu_filter) { - Intent intent = new Intent(this, FilterActivity.class); - startActivity(intent); - return true; - } - // open status editor - else if (item.getItemId() == R.id.menu_post) { - Intent intent = new Intent(this, StatusEditor.class); - startActivity(intent); - return true; - } - // open app settings - else if (item.getItemId() == R.id.menu_settings) { - Intent intent = new Intent(this, SettingsActivity.class); - activityResultLauncher.launch(intent); - return true; - } // theme expanded search view - else if (item.getItemId() == R.id.menu_search) { + if (item.getItemId() == R.id.menu_search) { SearchView searchView = (SearchView) item.getActionView(); AppStyles.setTheme(searchView, Color.TRANSPARENT); return true; } - // open message editor - else if (item.getItemId() == R.id.menu_message) { - Intent intent = new Intent(this, MessageEditor.class); - startActivity(intent); - return true; - } - // open account manager - else if (item.getItemId() == R.id.menu_account) { - Intent intent = new Intent(this, AccountActivity.class); - activityResultLauncher.launch(intent); - return true; - } return super.onOptionsItemSelected(item); } @Override - public void onBackPressed() { - if (viewPager.getCurrentItem() > 0) { - viewPager.setCurrentItem(0); - } else { - super.onBackPressed(); + public boolean onNavigationItemSelected(@NonNull MenuItem item) { + // open filter page + if (item.getItemId() == R.id.menu_navigator_filter) { + Intent intent = new Intent(this, FilterActivity.class); + startActivity(intent); + return true; } + // open status editor + else if (item.getItemId() == R.id.menu_navigator_status) { + Intent intent = new Intent(this, StatusEditor.class); + startActivity(intent); + return true; + } + // open app settings + else if (item.getItemId() == R.id.menu_navigator_settings) { + Intent intent = new Intent(this, SettingsActivity.class); + activityResultLauncher.launch(intent); + return true; + } + // open account manager + else if (item.getItemId() == R.id.menu_navigator_account) { + Intent intent = new Intent(this, AccountActivity.class); + activityResultLauncher.launch(intent); + return true; + } + // open user lists + else if (item.getItemId() == R.id.menu_navigator_lists) { + Intent intent = new Intent(this, UserlistsActivity.class); + intent.putExtra(UserlistsActivity.KEY_ID, settings.getLogin().getId()); + startActivity(intent); + } + return false; } @@ -252,13 +328,69 @@ public class MainActivity extends AppCompatActivity implements ActivityResultCal } } + + @Override + public void onClick(View v) { + if (v.getId() == R.id.navogation_header_root) { + Intent intent = new Intent(this, ProfileActivity.class); + if (currentUser != null) + intent.putExtra(ProfileActivity.KEY_USER, currentUser); + else + intent.putExtra(ProfileActivity.KEY_ID, settings.getLogin().getId()); + activityResultLauncher.launch(intent); + } else if (v.getId() == R.id.home_post) { + Intent intent = new Intent(this, StatusEditor.class); + startActivity(intent); + } + } + + + @Override + public void onResult(@NonNull UserResult userResult) { + if (userResult.user != null) { + setCurrentUser(userResult.user); + } + } + /** * */ private void setStyle() { - AppStyles.setTheme(root); - AppStyles.setOverflowIcon(toolbar, settings.getIconColor()); + AppStyles.setTheme(drawerLayout); tabSelector.addTabIcons(settings.getLogin().getConfiguration().getHomeTabIcons()); tabSelector.updateTheme(); } + + /** + * set current user information to navigation drawer + * + * @param user user information + */ + private void setCurrentUser(@Nullable User user) { + currentUser = user; + if (user != null) { + followingCount.setText(StringUtils.NUMBER_FORMAT.format(user.getFollowing())); + followerCount.setText(StringUtils.NUMBER_FORMAT.format(user.getFollower())); + screenname.setText(user.getScreenname()); + if (!user.getUsername().trim().isEmpty() && user.getEmojis().length > 0) { + Spannable usernameSpan = new SpannableString(user.getUsername()); + usernameSpan = EmojiUtils.removeTags(usernameSpan); + username.setText(usernameSpan); + } else { + username.setText(user.getUsername()); + } + Drawable placeholder = new ColorDrawable(IMAGE_PLACEHOLDER_COLOR); + if (!user.getProfileImageThumbnailUrl().isEmpty()) { + picasso.load(user.getProfileImageThumbnailUrl()).placeholder(placeholder).into(profileImage); + } else { + profileImage.setImageDrawable(placeholder); + } + } else { + profileImage.setImageResource(0); + followingCount.setText(""); + followerCount.setText(""); + screenname.setText(""); + username.setText(""); + } + } } \ No newline at end of file diff --git a/app/src/main/res/drawable/menu.xml b/app/src/main/res/drawable/menu.xml new file mode 100644 index 00000000..52f21bc5 --- /dev/null +++ b/app/src/main/res/drawable/menu.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/layout/navigation_header.xml b/app/src/main/res/layout/navigation_header.xml new file mode 100644 index 00000000..a5af652d --- /dev/null +++ b/app/src/main/res/layout/navigation_header.xml @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/page_main.xml b/app/src/main/res/layout/page_main.xml index 3a4d0376..03f77460 100644 --- a/app/src/main/res/layout/page_main.xml +++ b/app/src/main/res/layout/page_main.xml @@ -1,27 +1,66 @@ - - - - - - + android:orientation="vertical"> - \ No newline at end of file + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/home.xml b/app/src/main/res/menu/home.xml index 2d45cbd2..280e64c5 100644 --- a/app/src/main/res/menu/home.xml +++ b/app/src/main/res/menu/home.xml @@ -9,35 +9,4 @@ app:actionViewClass="androidx.appcompat.widget.SearchView" app:showAsAction="always|collapseActionView" /> - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/menu/main_navigation.xml b/app/src/main/res/menu/main_navigation.xml new file mode 100644 index 00000000..0122f002 --- /dev/null +++ b/app/src/main/res/menu/main_navigation.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index 493833bc..c5798640 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -200,6 +200,7 @@ @dimen/toolbar_height + 20dp @dimen/toolbar_height @@ -380,4 +381,9 @@ 5dp + + 10dp + 8dp + 5dp + \ No newline at end of file