This commit is contained in:
2020-08-31 21:54:31 -07:00
committed by Tom Hicks
parent 2a963cea0a
commit 5113283550
27 changed files with 258 additions and 805 deletions

View File

@@ -1,118 +1,30 @@
package com.majinnaibu.monstercards;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.view.MenuItem;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.navigation.NavController;
import androidx.navigation.NavDirections;
import androidx.navigation.fragment.NavHostFragment;
import androidx.navigation.ui.AppBarConfiguration;
import androidx.navigation.ui.NavigationUI;
import com.google.android.material.bottomnavigation.BottomNavigationView;
import com.majinnaibu.monstercards.helpers.StringHelper;
import com.majinnaibu.monstercards.init.AppCenterInitializer;
import com.majinnaibu.monstercards.init.FlipperInitializer;
import com.majinnaibu.monstercards.utils.Logger;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Objects;
import androidx.appcompat.app.AppCompatActivity;
import androidx.navigation.NavController;
import androidx.navigation.Navigation;
import androidx.navigation.ui.AppBarConfiguration;
import androidx.navigation.ui.NavigationUI;
public class MainActivity extends AppCompatActivity {
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
if (item.getItemId() == android.R.id.home) {
getOnBackPressedDispatcher().onBackPressed();
return true;
}
return super.onOptionsItemSelected(item);
}
@SuppressWarnings("ConstantConditions")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
AppCenterInitializer.init(getApplication());
setContentView(R.layout.activity_main);
BottomNavigationView navView = findViewById(R.id.nav_view);
// Passing each menu ID as a set of Ids because each
// menu should be considered as top level destinations.
AppBarConfiguration appBarConfiguration = new AppBarConfiguration.Builder(
R.id.navigation_search,
R.id.navigation_dashboard,
R.id.navigation_collections,
R.id.navigation_library)
R.id.navigation_home, R.id.navigation_dashboard, R.id.navigation_notifications)
.build();
NavHostFragment navHostFragment = (NavHostFragment) getSupportFragmentManager().findFragmentById(R.id.nav_host_fragment);
NavController navController = navHostFragment.getNavController();
navController.addOnDestinationChangedListener(FlipperInitializer::sendNavigationEvent);
NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration);
NavigationUI.setupWithNavController(navView, navController);
onNewIntent(getIntent());
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
String json = readMonsterJSONFromIntent(intent);
if (!StringHelper.isNullOrEmpty(json)) {
NavHostFragment navHostFragment = Objects.requireNonNull((NavHostFragment) getSupportFragmentManager().findFragmentById(R.id.nav_host_fragment));
NavController navController = navHostFragment.getNavController();
NavDirections action = MobileNavigationDirections.actionGlobalMonsterImportFragment(json);
navController.navigate(action);
}
}
@Nullable
private String readMonsterJSONFromIntent(@NonNull Intent intent) {
String action = intent.getAction();
Bundle extras = intent.getExtras();
String type = intent.getType();
String json;
Uri uri = null;
if ("android.intent.action.SEND".equals(action) && "text/plain".equals(type)) {
uri = extras.getParcelable("android.intent.extra.STREAM");
} else if ("android.intent.action.VIEW".equals(action) && ("text/plain".equals(type) || "application/octet-stream".equals(type))) {
uri = intent.getData();
} else {
Logger.logError(String.format("unexpected launch configuration action: %s, type: %s", action, type));
}
if (uri == null) {
return null;
}
json = readContentsOfUri(uri);
if (StringHelper.isNullOrEmpty(json)) {
return null;
}
return json;
}
@Nullable
private String readContentsOfUri(Uri uri) {
StringBuilder builder = new StringBuilder();
try (InputStream inputStream =
getContentResolver().openInputStream(uri);
BufferedReader reader = new BufferedReader(
new InputStreamReader(Objects.requireNonNull(inputStream)))) {
String line;
while ((line = reader.readLine()) != null) {
builder.append(line);
}
} catch (IOException e) {
Logger.logError("error reading file", e);
return null;
}
return builder.toString();
}
}

View File

@@ -1,84 +1,35 @@
package com.majinnaibu.monstercards.ui.dashboard;
import android.content.Context;
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.lifecycle.LiveData;
import androidx.lifecycle.ViewModelProvider;
import androidx.navigation.NavDirections;
import androidx.navigation.Navigation;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProviders;
import com.majinnaibu.monstercards.R;
import com.majinnaibu.monstercards.models.Monster;
import com.majinnaibu.monstercards.ui.shared.MCFragment;
import com.majinnaibu.monstercards.utils.Logger;
import java.util.List;
import java.util.Locale;
public class DashboardFragment extends Fragment {
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
import io.reactivex.rxjava3.schedulers.Schedulers;
public class DashboardFragment extends MCFragment {
private DashboardViewModel mViewModel;
private ViewHolder mHolder;
private DashboardRecyclerViewAdapter mAdapter;
private DashboardViewModel dashboardViewModel;
public View onCreateView(@NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
mViewModel = new ViewModelProvider(this).get(DashboardViewModel.class);
dashboardViewModel =
ViewModelProviders.of(this).get(DashboardViewModel.class);
View root = inflater.inflate(R.layout.fragment_dashboard, container, false);
mHolder = new ViewHolder(root);
setupRecyclerView(mHolder.list);
getMonsterRepository()
.getMonsters()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(monsters -> mViewModel.setMonsters(monsters));
return root;
}
private void setupRecyclerView(@NonNull RecyclerView recyclerView) {
int columnCount = Math.max(1, getResources().getConfiguration().screenWidthDp / 396);
Logger.logWTF(String.format(Locale.US, "Setting column count to %d", columnCount));
Context context = requireContext();
GridLayoutManager layoutManager = new GridLayoutManager(context, columnCount);
recyclerView.setLayoutManager(layoutManager);
LiveData<List<Monster>> monsterData = mViewModel.getMonsters();
mAdapter = new DashboardRecyclerViewAdapter(monster -> {
if (monster != null) {
navigateToMonsterDetail(monster);
} else {
Logger.logError("Can't navigate to MonsterDetailFragment with a null monster");
final TextView textView = root.findViewById(R.id.text_dashboard);
dashboardViewModel.getText().observe(getViewLifecycleOwner(), new Observer<String>() {
@Override
public void onChanged(@Nullable String s) {
textView.setText(s);
}
});
if (monsterData != null) {
monsterData.observe(getViewLifecycleOwner(), monsters -> mAdapter.submitList(monsters));
}
recyclerView.setAdapter(mAdapter);
return root;
}
private void navigateToMonsterDetail(Monster monster) {
NavDirections action = DashboardFragmentDirections.actionNavigationDashboardToNavigationMonster(monster.id.toString());
Navigation.findNavController(requireView()).navigate(action);
}
private static class ViewHolder {
final RecyclerView list;
ViewHolder(View root) {
list = root.findViewById(R.id.list);
}
}
}

View File

@@ -4,23 +4,16 @@ import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
import com.majinnaibu.monstercards.models.Monster;
import java.util.ArrayList;
import java.util.List;
public class DashboardViewModel extends ViewModel {
private final MutableLiveData<List<Monster>> mMonsters;
private MutableLiveData<String> mText;
public DashboardViewModel() {
mMonsters = new MutableLiveData<>(new ArrayList<>());
mText = new MutableLiveData<>();
mText.setValue("This is dashboard fragment");
}
public LiveData<List<Monster>> getMonsters() {
return mMonsters;
}
public void setMonsters(List<Monster> monsters) {
mMonsters.setValue(monsters);
public LiveData<String> getText() {
return mText;
}
}

View File

@@ -0,0 +1,35 @@
package com.majinnaibu.monstercards.ui.home;
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.lifecycle.Observer;
import androidx.lifecycle.ViewModelProviders;
import com.majinnaibu.monstercards.R;
public class HomeFragment extends Fragment {
private HomeViewModel homeViewModel;
public View onCreateView(@NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
homeViewModel =
ViewModelProviders.of(this).get(HomeViewModel.class);
View root = inflater.inflate(R.layout.fragment_home, container, false);
final TextView textView = root.findViewById(R.id.text_home);
homeViewModel.getText().observe(getViewLifecycleOwner(), new Observer<String>() {
@Override
public void onChanged(@Nullable String s) {
textView.setText(s);
}
});
return root;
}
}

View File

@@ -0,0 +1,19 @@
package com.majinnaibu.monstercards.ui.home;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
public class HomeViewModel extends ViewModel {
private MutableLiveData<String> mText;
public HomeViewModel() {
mText = new MutableLiveData<>();
mText.setValue("This is home fragment");
}
public LiveData<String> getText() {
return mText;
}
}

View File

@@ -0,0 +1,35 @@
package com.majinnaibu.monstercards.ui.notifications;
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.lifecycle.Observer;
import androidx.lifecycle.ViewModelProviders;
import com.majinnaibu.monstercards.R;
public class NotificationsFragment extends Fragment {
private NotificationsViewModel notificationsViewModel;
public View onCreateView(@NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
notificationsViewModel =
ViewModelProviders.of(this).get(NotificationsViewModel.class);
View root = inflater.inflate(R.layout.fragment_notifications, container, false);
final TextView textView = root.findViewById(R.id.text_notifications);
notificationsViewModel.getText().observe(getViewLifecycleOwner(), new Observer<String>() {
@Override
public void onChanged(@Nullable String s) {
textView.setText(s);
}
});
return root;
}
}

View File

@@ -0,0 +1,19 @@
package com.majinnaibu.monstercards.ui.notifications;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
public class NotificationsViewModel extends ViewModel {
private MutableLiveData<String> mText;
public NotificationsViewModel() {
mText = new MutableLiveData<>();
mText.setValue("This is notifications fragment");
}
public LiveData<String> getText() {
return mText;
}
}