The application architecture was refactored (the application now uses the MVP architectural pattern), and dynamic loading of all levels of the tree is implemented.

This commit is contained in:
ChronosX88 2019-01-04 21:19:13 +04:00
parent bb349e6b83
commit 001889aa14
No known key found for this signature in database
GPG Key ID: 8F92E090A87804AA
21 changed files with 456 additions and 268 deletions

View File

@ -29,7 +29,7 @@
</value> </value>
</option> </option>
</component> </component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" project-jdk-name="1.8" project-jdk-type="JavaSDK"> <component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" /> <output url="file://$PROJECT_DIR$/build/classes" />
</component> </component>
<component name="ProjectType"> <component name="ProjectType">

View File

@ -10,6 +10,10 @@ android {
versionName "1.0" versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
} }
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
buildTypes { buildTypes {
release { release {
minifyEnabled false minifyEnabled false
@ -24,6 +28,7 @@ dependencies {
implementation 'com.android.support:appcompat-v7:27.1.1' implementation 'com.android.support:appcompat-v7:27.1.1'
implementation 'com.android.support:design:27.1.1' implementation 'com.android.support:design:27.1.1'
implementation 'com.android.support.constraint:constraint-layout:1.1.3' implementation 'com.android.support.constraint:constraint-layout:1.1.3'
implementation 'com.github.msteinbeck:sig4j:1.0.1'
implementation 'me.texy.treeview:treeview_lib:1.0.4' implementation 'me.texy.treeview:treeview_lib:1.0.4'
implementation 'com.google.code.gson:gson:2.8.2' implementation 'com.google.code.gson:gson:2.8.2'
implementation 'com.squareup.retrofit2:retrofit:2.1.0' implementation 'com.squareup.retrofit2:retrofit:2.1.0'

View File

@ -12,7 +12,7 @@
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/AppTheme"> android:theme="@style/AppTheme">
<activity <activity
android:name=".MainActivity" android:name=".view.MainActivity"
android:label="@string/app_name" android:label="@string/app_name"
android:theme="@style/AppTheme.NoActionBar"> android:theme="@style/AppTheme.NoActionBar">
<intent-filter> <intent-filter>
@ -21,8 +21,8 @@
<category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter> </intent-filter>
</activity> </activity>
<activity android:name=".SettingsActivity" /> <activity android:name=".view.SettingsActivity" />
<activity android:name=".AboutActivity"></activity> <activity android:name=".view.AboutActivity"></activity>
</application> </application>
</manifest> </manifest>

View File

@ -1,247 +0,0 @@
package ru.volgorobot.vrcatalog;
import android.content.AsyncQueryHandler;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.AsyncTask;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.design.widget.NavigationView;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import me.texy.treeview.TreeNode;
import me.texy.treeview.TreeView;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import ru.volgorobot.vrcatalog.additional.NodeViewFactory;
import ru.volgorobot.vrcatalog.api.Controller;
import ru.volgorobot.vrcatalog.api.VRApi;
import ru.volgorobot.vrcatalog.model.FirstLevelModel;
import ru.volgorobot.vrcatalog.model.SecondLevelModel;
import ru.volgorobot.vrcatalog.model.ThirdLevelModel;
public class MainActivity extends AppCompatActivity
implements NavigationView.OnNavigationItemSelectedListener, SwipeRefreshLayout.OnRefreshListener {
private TreeView treeView;
private VRApi vrApi;
private List<FirstLevelModel> firstLevelObjects = new ArrayList<>();
private List<TreeNode> firstLevelNodes = new ArrayList<>();
private List<SecondLevelModel> secondLevelObjects = new ArrayList<>();
private List<ThirdLevelModel> thirdLevelObjects = new ArrayList<>();
private TreeNode rootNode = TreeNode.root();
private SwipeRefreshLayout mSwipeRefreshLayout;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
DrawerLayout drawer = findViewById(R.id.drawer_layout);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawer.addDrawerListener(toggle);
toggle.syncState();
NavigationView navigationView = findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(this);
mSwipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.swipeRefreshLayout);
mSwipeRefreshLayout.setOnRefreshListener(MainActivity.this);
mSwipeRefreshLayout.setColorSchemeResources(R.color.colorPrimary);
try {
getTreeData(false);
} catch (IllegalStateException e) {
//
}
treeView = new TreeView(rootNode, MainActivity.this, new NodeViewFactory());
((ViewGroup) findViewById(R.id.treeViewContainer)).addView(treeView.getView());
}
@Override
public void onBackPressed() {
DrawerLayout drawer = findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else {
super.onBackPressed();
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
return super.onOptionsItemSelected(item);
}
@SuppressWarnings("StatementWithEmptyBody")
@Override
public boolean onNavigationItemSelected(MenuItem item) {
// Handle navigation view item clicks here.
int id = item.getItemId();
NavigationView navView = findViewById(R.id.nav_view);
if (id == R.id.nav_settings) {
startActivity(new Intent(this, SettingsActivity.class));
} else if (id == R.id.nav_about) {
startActivity(new Intent(this, AboutActivity.class));
}
DrawerLayout drawer = findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
return true;
}
private void fillRootNode() {
for (int i = 0; i < firstLevelObjects.size(); i++) {
firstLevelNodes.add(new TreeNode(firstLevelObjects.get(i).getName()));
firstLevelNodes.get(i).setLevel(0);
firstLevelNodes.get(i).setChildren(getSecondLevelNodesByParentID(firstLevelObjects.get(i).getID()));
}
rootNode.setChildren(firstLevelNodes);
}
private ArrayList<TreeNode> getSecondLevelNodesByParentID(int parentTypeID) {
ArrayList<SecondLevelModel> objects = new ArrayList<>();
for (int i = 0; i < secondLevelObjects.size(); i++) {
if(secondLevelObjects.get(i).getDetailTypeId() == parentTypeID) {
objects.add(secondLevelObjects.get(i));
}
}
ArrayList<TreeNode> nodes = new ArrayList<>();
for (int i = 0; i < objects.size(); i++) {
nodes.add(new TreeNode(objects.get(i).getName()));
nodes.get(i).setLevel(1);
}
return nodes;
}
private ArrayList<TreeNode> getThirdLevelNodesByParentName(String parentName) {
ArrayList<ThirdLevelModel> objects = new ArrayList<>();
for (int i = 0; i < thirdLevelObjects.size(); i++) {
if(thirdLevelObjects.get(i).getName().equals(parentName)) {
objects.add(thirdLevelObjects.get(i));
}
}
ArrayList<TreeNode> nodes = new ArrayList<>();
for (int i = 0; i < objects.size(); i++) {
nodes.add(new TreeNode(objects.get(i).getName()));
nodes.get(i).setLevel(2);
}
return nodes;
}
@Override
public void onRefresh() {
mSwipeRefreshLayout.setRefreshing(true);
try {
getTreeData(true);
} catch (IllegalStateException e) {
//
}
}
private void getTreeData(final boolean clean) throws IllegalStateException {
mSwipeRefreshLayout.setRefreshing(true);
if(clean) {
firstLevelNodes.removeAll(firstLevelNodes);
firstLevelObjects.removeAll(firstLevelObjects);
secondLevelObjects.removeAll(secondLevelObjects);
}
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
String baseURL = sharedPreferences.getString("addressOfServer", "");
try {
vrApi = Controller.getApi(baseURL, this);
} catch(IllegalStateException e) {
throw new IllegalStateException();
}
class GetTreeData extends AsyncTask<Void, Void, Integer> {
@Override
protected Integer doInBackground(Void... voids) {
try {
Response<List<FirstLevelModel>> firstLevelResponse = vrApi.getFirstLevel().execute();
if(firstLevelResponse.isSuccessful()) {
firstLevelObjects.addAll(firstLevelResponse.body());
for (int i = 0; i < firstLevelObjects.size(); i++) {
Response<List<SecondLevelModel>> secondLevelResponse = vrApi.getSecondLevel(firstLevelObjects.get(i).getID()).execute();
if(secondLevelResponse.isSuccessful()) {
secondLevelObjects.addAll(secondLevelResponse.body());
} else {
return 2;
}
}
} else {
return 2;
}
} catch (Exception e) {
return 1;
}
return 0;
}
@Override
protected void onPostExecute(Integer integer) {
super.onPostExecute(integer);
if(integer == 0) {
fillRootNode();
treeView.refreshTreeView();
mSwipeRefreshLayout.setRefreshing(false);
} else if(integer == 1) {
onFailureAnswer(1);
} else if(integer == 2) {
onFailureAnswer(2);
}
}
}
new GetTreeData().execute();
}
private void onFailureAnswer(int errorCode) {
switch (errorCode) {
case 1: {
Toast.makeText(MainActivity.this, "Ошибка сети. Проверьте подключение к сети или данные подключения к API!", Toast.LENGTH_LONG).show();
Log.e("VRCatalog", "Network Error! Re-check your connection credentials or network settings! Technical info: null");
mSwipeRefreshLayout.setRefreshing(false);
break;
}
case 2: {
Toast.makeText(MainActivity.this, "Ответ от сервера неверен! Перепроверьте данные подключения!", Toast.LENGTH_LONG).show();
Log.e("VRCatalog", "Answer of server is wrong! Re-check your connection credentials! Technical info: null");
mSwipeRefreshLayout.setRefreshing(false);
break;
}
}
}
}

View File

@ -0,0 +1,32 @@
package ru.volgorobot.vrcatalog;
import android.widget.ImageView;
import com.github.msteinbeck.sig4j.signal.Signal1;
import java.util.ArrayList;
import ru.volgorobot.vrcatalog.model.FirstLevelModel;
import ru.volgorobot.vrcatalog.model.SecondLevelModel;
import ru.volgorobot.vrcatalog.model.ThirdLevelModel;
public interface MainContract {
interface MainActivityView {
void swipeLayoutSetRefreshing(boolean state);
void buildFirstLevelTree(ArrayList<FirstLevelModel> firstLevelModels);
void onFailureAnswer(int errorCode);
void refreshTree();
}
interface Presenter {
void getFirstLevel();
void failureAnswerSlot(int errorCode);
}
interface MainModel {
Signal1<Integer> errorSignal = new Signal1<>();
ArrayList<FirstLevelModel> getFirstLevel();
ArrayList<SecondLevelModel> getSecondLevelByParentID(int parentID);
ArrayList<ThirdLevelModel> getThirdLevelByParentID(int parentID);
}
}

View File

@ -0,0 +1,59 @@
package ru.volgorobot.vrcatalog;
import android.content.Context;
import android.os.AsyncTask;
import java.util.ArrayList;
import ru.volgorobot.vrcatalog.model.CoreModel;
import ru.volgorobot.vrcatalog.model.FirstLevelModel;
public class MainPresenter implements MainContract.Presenter {
private MainContract.MainActivityView mView;
private MainContract.MainModel coreModel;
public MainPresenter(MainContract.MainActivityView mainActivityView, Context context) {
this.mView = mainActivityView;
try {
this.coreModel = new CoreModel(context);
} catch (IllegalStateException e) {
mView.onFailureAnswer(3);
}
coreModel.errorSignal.connect(this::failureAnswerSlot);
}
@Override
public void getFirstLevel() {
new AsyncTask<Void, Void, ArrayList<FirstLevelModel>>() {
@Override
protected ArrayList<FirstLevelModel> doInBackground(Void... voids) {
ArrayList<FirstLevelModel> firstLevelModels = coreModel.getFirstLevel();
return firstLevelModels;
}
@Override
protected void onPostExecute(ArrayList<FirstLevelModel> firstLevelModels) {
mView.buildFirstLevelTree(firstLevelModels);
}
}.execute();
mView.swipeLayoutSetRefreshing(false);
}
@Override
public void failureAnswerSlot(int errorCode) {
switch (errorCode) {
case 1: {
mView.onFailureAnswer(1);
break;
}
case 2: {
mView.onFailureAnswer(2);
break;
}
case 3: {
mView.onFailureAnswer(3);
break;
}
}
}
}

View File

@ -1,21 +1,31 @@
package ru.volgorobot.vrcatalog.additional; package ru.volgorobot.vrcatalog.additional;
import android.content.Context;
import android.view.View; import android.view.View;
import me.texy.treeview.base.BaseNodeViewBinder; import me.texy.treeview.base.BaseNodeViewBinder;
import me.texy.treeview.base.BaseNodeViewFactory; import me.texy.treeview.base.BaseNodeViewFactory;
import ru.volgorobot.vrcatalog.MainContract;
import ru.volgorobot.vrcatalog.nodeViewBinders.FirstLevelNodeViewBinder; import ru.volgorobot.vrcatalog.nodeViewBinders.FirstLevelNodeViewBinder;
import ru.volgorobot.vrcatalog.nodeViewBinders.SecondLevelNodeViewBinder; import ru.volgorobot.vrcatalog.nodeViewBinders.SecondLevelNodeViewBinder;
import ru.volgorobot.vrcatalog.nodeViewBinders.ThirdLevelNodeViewBinder; import ru.volgorobot.vrcatalog.nodeViewBinders.ThirdLevelNodeViewBinder;
public class NodeViewFactory extends BaseNodeViewFactory { public class NodeViewFactory extends BaseNodeViewFactory {
MainContract.MainActivityView mView;
Context context;
public NodeViewFactory(Context context, MainContract.MainActivityView mView) {
this.mView = mView;
this.context = context;
}
@Override @Override
public BaseNodeViewBinder getNodeViewBinder(View view, int level) { public BaseNodeViewBinder getNodeViewBinder(View view, int level) {
switch (level) { switch (level) {
case 0: case 0:
return new FirstLevelNodeViewBinder(view); return new FirstLevelNodeViewBinder(view, context, mView);
case 1: case 1:
return new SecondLevelNodeViewBinder(view); return new SecondLevelNodeViewBinder(view, context, mView);
case 2: case 2:
return new ThirdLevelNodeViewBinder(view); return new ThirdLevelNodeViewBinder(view);
default: default:

View File

@ -11,14 +11,12 @@ import retrofit2.converter.gson.GsonConverterFactory;
public class Controller { public class Controller {
private static String baseURL; private static String baseURL;
private static Context context;
private static Retrofit retrofit; private static Retrofit retrofit;
private static VRApi vrApi; private static VRApi vrApi;
public static VRApi getApi(String baseURL1, Context context1) throws IllegalStateException { public static VRApi getApi(String baseURL1) throws IllegalStateException {
baseURL = baseURL1; baseURL = baseURL1;
context = context1;
Gson gson = new GsonBuilder() Gson gson = new GsonBuilder()
.setLenient() .setLenient()
.create(); .create();
@ -38,7 +36,6 @@ public class Controller {
.addConverterFactory(GsonConverterFactory.create(gson)) .addConverterFactory(GsonConverterFactory.create(gson))
.build(); .build();
} catch(Exception e) { } catch(Exception e) {
Toast.makeText(context, "Вы ввели неверный URL. Пример: http://example.ru", Toast.LENGTH_LONG).show();
throw new IllegalStateException(); throw new IllegalStateException();
} }
} }

View File

@ -0,0 +1,80 @@
package ru.volgorobot.vrcatalog.model;
import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import com.github.msteinbeck.sig4j.signal.Signal1;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import retrofit2.Response;
import ru.volgorobot.vrcatalog.MainContract;
import ru.volgorobot.vrcatalog.api.Controller;
import ru.volgorobot.vrcatalog.api.VRApi;
public class CoreModel implements MainContract.MainModel {
private Context context;
private VRApi vrApi;
public final Signal1<Integer> errorSignal = new Signal1<>();
public CoreModel(Context context) throws IllegalStateException {
this.context = context;
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
String baseURL = sharedPreferences.getString("addressOfServer", "");
try {
vrApi = Controller.getApi(baseURL);
} catch(IllegalStateException e) {
throw new IllegalStateException();
}
}
@Override
public ArrayList<FirstLevelModel> getFirstLevel() {
final ArrayList<FirstLevelModel> firstLevelModels = new ArrayList<>();
try {
Response<List<FirstLevelModel>> response = vrApi.getFirstLevel().execute();
if(response.isSuccessful()) {
firstLevelModels.addAll(response.body());
} else {
errorSignal.emit(2);
}
} catch (IOException e) {
errorSignal.emit(1);
}
return firstLevelModels;
}
@Override
public ArrayList<SecondLevelModel> getSecondLevelByParentID(int parentID) {
final ArrayList<SecondLevelModel> secondLevelModels = new ArrayList<>();
try {
Response<List<SecondLevelModel>> response = vrApi.getSecondLevel(parentID).execute();
if(response.isSuccessful()) {
secondLevelModels.addAll(response.body());
} else {
errorSignal.emit(2);
}
} catch (IOException e) {
errorSignal.emit(1);
}
return secondLevelModels;
}
@Override
public ArrayList<ThirdLevelModel> getThirdLevelByParentID(int parentID) {
final ArrayList<ThirdLevelModel> thirdLevelModels = new ArrayList<>();
try {
Response<List<ThirdLevelModel>> response = vrApi.getDetails(parentID).execute();
if(response.isSuccessful()) {
thirdLevelModels.addAll(response.body());
} else {
errorSignal.emit(2);
}
} catch (IOException e) {
errorSignal.emit(1);
}
return thirdLevelModels;
}
}

View File

@ -40,4 +40,7 @@ public class FirstLevelModel {
this.iD = iD; this.iD = iD;
} }
public String toString() {
return name;
}
} }

View File

@ -51,4 +51,7 @@ public class SecondLevelModel {
this.name = name; this.name = name;
} }
public String toString() {
return name;
}
} }

View File

@ -59,4 +59,7 @@ public class ThirdLevelModel {
this.name = name; this.name = name;
} }
public String toString() {
return name;
}
} }

View File

@ -1,21 +1,34 @@
package ru.volgorobot.vrcatalog.nodeViewBinders; package ru.volgorobot.vrcatalog.nodeViewBinders;
import android.content.Context;
import android.os.AsyncTask;
import android.view.View; import android.view.View;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import java.util.ArrayList;
import me.texy.treeview.TreeNode; import me.texy.treeview.TreeNode;
import me.texy.treeview.base.BaseNodeViewBinder; import me.texy.treeview.base.BaseNodeViewBinder;
import ru.volgorobot.vrcatalog.MainContract;
import ru.volgorobot.vrcatalog.R; import ru.volgorobot.vrcatalog.R;
import ru.volgorobot.vrcatalog.model.CoreModel;
import ru.volgorobot.vrcatalog.model.FirstLevelModel;
import ru.volgorobot.vrcatalog.model.SecondLevelModel;
public class FirstLevelNodeViewBinder extends BaseNodeViewBinder { public class FirstLevelNodeViewBinder extends BaseNodeViewBinder {
TextView textView; TextView textView;
ImageView imageView; ImageView imageView;
CoreModel coreModel;
MainContract.MainActivityView mView;
public FirstLevelNodeViewBinder(View itemView) { public FirstLevelNodeViewBinder(View itemView, Context context, MainContract.MainActivityView mView) {
super(itemView); super(itemView);
textView = (TextView) itemView.findViewById(R.id.node_name_view); textView = (TextView) itemView.findViewById(R.id.node_name_view);
imageView = (ImageView) itemView.findViewById(R.id.arrow_img); imageView = (ImageView) itemView.findViewById(R.id.arrow_img);
this.coreModel = new CoreModel(context);
this.mView = mView;
coreModel.errorSignal.connect(mView::onFailureAnswer);
} }
@Override @Override
@ -31,7 +44,35 @@ public class FirstLevelNodeViewBinder extends BaseNodeViewBinder {
@Override @Override
public void onNodeToggled(TreeNode treeNode, boolean expand) { public void onNodeToggled(TreeNode treeNode, boolean expand) {
if(expand) { if(expand) {
FirstLevelModel firstLevelModel = (FirstLevelModel) treeNode.getValue();
new AsyncTask<Void, Void, ArrayList<SecondLevelModel>>() {
@Override
protected void onPreExecute() {
super.onPreExecute();
mView.swipeLayoutSetRefreshing(true);
}
@Override
protected ArrayList<SecondLevelModel> doInBackground(Void... voids) {
ArrayList<SecondLevelModel> secondLevelModels = coreModel.getSecondLevelByParentID(firstLevelModel.getID());
return secondLevelModels;
}
@Override
protected void onPostExecute(ArrayList<SecondLevelModel> secondLevelModels) {
super.onPostExecute(secondLevelModels);
ArrayList<TreeNode> treeNodes = new ArrayList<>();
for (int i = 0; i < secondLevelModels.size(); i++) {
TreeNode treeNode1 = new TreeNode(secondLevelModels.get(i));
treeNode1.setLevel(1);
treeNodes.add(treeNode1);
}
treeNode.setChildren(treeNodes);
mView.refreshTree();
mView.swipeLayoutSetRefreshing(false);
imageView.animate().rotation(90).setDuration(200).start(); imageView.animate().rotation(90).setDuration(200).start();
}
}.execute();
} else { } else {
imageView.animate().rotation(0).setDuration(200).start(); imageView.animate().rotation(0).setDuration(200).start();
} }

View File

@ -1,21 +1,35 @@
package ru.volgorobot.vrcatalog.nodeViewBinders; package ru.volgorobot.vrcatalog.nodeViewBinders;
import android.content.Context;
import android.os.AsyncTask;
import android.view.View; import android.view.View;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import java.util.ArrayList;
import me.texy.treeview.TreeNode; import me.texy.treeview.TreeNode;
import me.texy.treeview.base.BaseNodeViewBinder; import me.texy.treeview.base.BaseNodeViewBinder;
import ru.volgorobot.vrcatalog.MainContract;
import ru.volgorobot.vrcatalog.R; import ru.volgorobot.vrcatalog.R;
import ru.volgorobot.vrcatalog.model.CoreModel;
import ru.volgorobot.vrcatalog.model.SecondLevelModel;
import ru.volgorobot.vrcatalog.model.ThirdLevelModel;
public class SecondLevelNodeViewBinder extends BaseNodeViewBinder { public class SecondLevelNodeViewBinder extends BaseNodeViewBinder {
TextView textView; TextView textView;
ImageView imageView; ImageView imageView;
MainContract.MainModel coreModel;
MainContract.MainActivityView mView;
public SecondLevelNodeViewBinder(View itemView) {
public SecondLevelNodeViewBinder(View itemView, Context context, MainContract.MainActivityView mView) {
super(itemView); super(itemView);
textView = (TextView) itemView.findViewById(R.id.node_name_view); textView = (TextView) itemView.findViewById(R.id.node_name_view);
imageView = (ImageView) itemView.findViewById(R.id.arrow_img); imageView = (ImageView) itemView.findViewById(R.id.arrow_img);
this.coreModel = new CoreModel(context);
this.mView = mView;
coreModel.errorSignal.connect(mView::onFailureAnswer);
} }
@Override @Override
@ -32,7 +46,35 @@ public class SecondLevelNodeViewBinder extends BaseNodeViewBinder {
@Override @Override
public void onNodeToggled(TreeNode treeNode, boolean expand) { public void onNodeToggled(TreeNode treeNode, boolean expand) {
if(expand) { if(expand) {
SecondLevelModel secondLevelModel = (SecondLevelModel) treeNode.getValue();
new AsyncTask<Void, Void, ArrayList<ThirdLevelModel>>() {
@Override
protected void onPreExecute() {
super.onPreExecute();
mView.swipeLayoutSetRefreshing(true);
}
@Override
protected ArrayList<ThirdLevelModel> doInBackground(Void... voids) {
ArrayList<ThirdLevelModel> thirdLevelModels = coreModel.getThirdLevelByParentID(secondLevelModel.getID());
return thirdLevelModels;
}
@Override
protected void onPostExecute(ArrayList<ThirdLevelModel> thirdLevelModels) {
super.onPostExecute(thirdLevelModels);
ArrayList<TreeNode> treeNodes = new ArrayList<>();
for (int i = 0; i < thirdLevelModels.size(); i++) {
TreeNode treeNode1 = new TreeNode(thirdLevelModels.get(i));
treeNode1.setLevel(2);
treeNodes.add(treeNode1);
}
treeNode.setChildren(treeNodes);
mView.refreshTree();
mView.swipeLayoutSetRefreshing(false);
imageView.animate().rotation(90).setDuration(200).start(); imageView.animate().rotation(90).setDuration(200).start();
}
}.execute();
} else { } else {
imageView.animate().rotation(0).setDuration(200).start(); imageView.animate().rotation(0).setDuration(200).start();
} }

View File

@ -1,10 +1,12 @@
package ru.volgorobot.vrcatalog; package ru.volgorobot.vrcatalog.view;
import android.os.Bundle; import android.os.Bundle;
import android.support.v7.app.AppCompatActivity; import android.support.v7.app.AppCompatActivity;
import android.view.Menu; import android.view.Menu;
import android.view.MenuItem; import android.view.MenuItem;
import ru.volgorobot.vrcatalog.R;
public class AboutActivity extends AppCompatActivity { public class AboutActivity extends AppCompatActivity {
@Override @Override

View File

@ -0,0 +1,156 @@
package ru.volgorobot.vrcatalog.view;
import android.content.Intent;
import android.os.Bundle;
import android.support.design.widget.NavigationView;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.MenuItem;
import android.view.ViewGroup;
import android.widget.Toast;
import java.util.ArrayList;
import me.texy.treeview.TreeNode;
import me.texy.treeview.TreeView;
import ru.volgorobot.vrcatalog.MainContract;
import ru.volgorobot.vrcatalog.MainPresenter;
import ru.volgorobot.vrcatalog.R;
import ru.volgorobot.vrcatalog.additional.NodeViewFactory;
import ru.volgorobot.vrcatalog.model.FirstLevelModel;
public class MainActivity extends AppCompatActivity
implements NavigationView.OnNavigationItemSelectedListener, SwipeRefreshLayout.OnRefreshListener, MainContract.MainActivityView {
private MainContract.Presenter mPresenter;
private TreeView treeView;
private TreeNode rootNode = TreeNode.root();
private SwipeRefreshLayout mSwipeRefreshLayout;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
DrawerLayout drawer = findViewById(R.id.drawer_layout);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawer.addDrawerListener(toggle);
toggle.syncState();
NavigationView navigationView = findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(this);
mSwipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.swipeRefreshLayout);
mSwipeRefreshLayout.setOnRefreshListener(MainActivity.this);
mSwipeRefreshLayout.setColorSchemeResources(R.color.colorPrimary);
mPresenter = new MainPresenter(this, MainActivity.this);
treeView = new TreeView(rootNode, MainActivity.this, new NodeViewFactory(MainActivity.this, this));
treeView.setItemAnimator(new DefaultItemAnimator());
((ViewGroup) findViewById(R.id.treeViewContainer)).addView(treeView.getView());
mSwipeRefreshLayout.setRefreshing(true);
mPresenter.getFirstLevel();
}
@Override
public void onBackPressed() {
DrawerLayout drawer = findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else {
super.onBackPressed();
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
return super.onOptionsItemSelected(item);
}
@SuppressWarnings("StatementWithEmptyBody")
@Override
public boolean onNavigationItemSelected(MenuItem item) {
// Handle navigation view item clicks here.
int id = item.getItemId();
NavigationView navView = findViewById(R.id.nav_view);
if (id == R.id.nav_settings) {
startActivity(new Intent(this, SettingsActivity.class));
} else if (id == R.id.nav_about) {
startActivity(new Intent(this, AboutActivity.class));
}
DrawerLayout drawer = findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
return true;
}
@Override
public void onRefresh() {
mSwipeRefreshLayout.setRefreshing(true);
mPresenter.getFirstLevel();
}
public void onFailureAnswer(int errorCode) {
switch (errorCode) {
case 1: {
Toast.makeText(MainActivity.this, "Ошибка сети. Проверьте подключение к сети или данные подключения к API!", Toast.LENGTH_LONG).show();
Log.e("VRCatalog", "Network Error! Re-check your connection credentials or network settings! Technical info: null");
mSwipeRefreshLayout.setRefreshing(false);
break;
}
case 2: {
Toast.makeText(MainActivity.this, "Ответ от сервера неверен! Перепроверьте данные подключения!", Toast.LENGTH_LONG).show();
Log.e("VRCatalog", "Answer of server is wrong! Re-check your connection credentials! Technical info: null");
mSwipeRefreshLayout.setRefreshing(false);
break;
}
case 3: {
Toast.makeText(this, "Вы ввели неверный URL. Пример: http://example.ru", Toast.LENGTH_LONG).show();
mSwipeRefreshLayout.setRefreshing(false);
break;
}
}
}
@Override
public void swipeLayoutSetRefreshing(boolean state) {
mSwipeRefreshLayout.setRefreshing(state);
}
@Override
public void buildFirstLevelTree(ArrayList<FirstLevelModel> firstLevelModels) {
ArrayList<TreeNode> treeNodes = new ArrayList<>();
for (int i = 0; i < firstLevelModels.size(); i++) {
TreeNode treeNode = new TreeNode(firstLevelModels.get(i));
treeNode.setLevel(0);
treeNodes.add(treeNode);
}
rootNode.setChildren(treeNodes);
treeView.refreshTreeView();
}
@Override
public void refreshTree() {
treeView.refreshTreeView();
}
}

View File

@ -1,8 +1,10 @@
package ru.volgorobot.vrcatalog; package ru.volgorobot.vrcatalog.view;
import android.os.Bundle; import android.os.Bundle;
import android.view.Menu; import android.view.Menu;
import android.view.MenuItem; import android.view.MenuItem;
import ru.volgorobot.vrcatalog.R;
import ru.volgorobot.vrcatalog.additional.AppCompatPreferenceActivity; import ru.volgorobot.vrcatalog.additional.AppCompatPreferenceActivity;
public class SettingsActivity extends AppCompatPreferenceActivity { public class SettingsActivity extends AppCompatPreferenceActivity {

View File

@ -5,7 +5,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:gravity="center" android:gravity="center"
tools:context=".AboutActivity"> tools:context=".view.AboutActivity">
<LinearLayout <LinearLayout
android:layout_width="wrap_content" android:layout_width="wrap_content"

View File

@ -4,7 +4,7 @@
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
tools:context=".MainActivity"> tools:context=".view.MainActivity">
<android.support.design.widget.AppBarLayout <android.support.design.widget.AppBarLayout
android:layout_width="match_parent" android:layout_width="match_parent"

View File

@ -5,7 +5,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior" app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:context=".MainActivity" tools:context=".view.MainActivity"
tools:showIn="@layout/app_bar_main" tools:showIn="@layout/app_bar_main"
android:orientation="horizontal" android:orientation="horizontal"
android:id="@+id/swipeRefreshLayout"> android:id="@+id/swipeRefreshLayout">