Skip to content

Lab4 #4

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 17 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .idea/.name

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

463 changes: 463 additions & 0 deletions .idea/dbnavigator.xml

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion .idea/gradle.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions .idea/inspectionProfiles/Project_Default.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

36 changes: 35 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,35 @@
# AndroidOracle
# AndroidRemoteOpenDataServers

## Preview
1. This project uses jdk 8;
2. This project uses MVVM architecture.
3. This project executes network request.
Use for this network clients OkHttp and Retrofit.
4. This project works with SQLite db using the Room library.

## Features
☑️ The application performs network requests to a remote
service on receiving data in GSON format using OkHttp clients
and/or Retrofit.

☑️ The received data is cached in the local database, on
case of loss of network connection. If the service or network
are not available, then the data is displayed in the interface of the application
local database. When requesting data, a check is performed
to match the data in the local database. If the data is from a remote
service have changed, then the data in the local database is updated.

☑️ The application consists of two screens. The first screen shows the data in a list.
When you click on any item in the list, it starts
another screen with detailed information when the item is selected.

## Launch guide
To run this project you will need to install this project in phone with Android Operating System.

## Program testing
<i><b>Main Activity</b></i><br>
![Main Activity](app/src/main/res/img/img_AT_holidays.jpg)
![Main Activity](app/src/main/res/img/img_AL_holidays.jpg)
<br><i><b>Details Activity</b></i><br>
For example, for country AT holidays<br>
![Main Activity](app/src/main/res/img/img_AT_holiday_NYD.jpg)
37 changes: 30 additions & 7 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ android {
buildToolsVersion "30.0.2"

defaultConfig {
applicationId "ua.gura.com.example.andriodoracle"
applicationId "ua.gura.com.example.androidoracle"
minSdkVersion 19
targetSdkVersion 30
versionCode 1
Expand All @@ -29,11 +29,34 @@ android {
}

dependencies {

implementation 'androidx.appcompat:appcompat:1.5.1'
implementation 'com.google.android.material:material:1.6.1'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'com.google.android.material:material:1.2.1'
implementation 'androidx.constraintlayout:constraintlayout:2.0.2'
testImplementation 'junit:junit:4.+'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'

implementation 'androidx.lifecycle:lifecycle-viewmodel:2.2.0'
implementation 'androidx.lifecycle:lifecycle-livedata:2.2.0'
implementation 'androidx.lifecycle:lifecycle-viewmodel-savedstate:2.2.0'
annotationProcessor "androidx.lifecycle:lifecycle-compiler:2.2.0"

implementation 'androidx.room:room-runtime:2.2.5'
annotationProcessor 'androidx.room:room-compiler:2.2.5'

implementation 'com.squareup.okhttp3:okhttp:3.9.0'
implementation 'com.squareup.okhttp3:logging-interceptor:3.9.0'

implementation 'com.squareup.retrofit2:retrofit:2.8.1'
implementation 'com.squareup.retrofit2:converter-gson:2.8.1'

implementation 'com.google.code.gson:gson:2.8.6'

implementation 'com.annimon:stream:1.2.1'

implementation 'androidx.recyclerview:recyclerview:1.1.0'




}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package ua.gura.com.example.andriodoracle;
package ua.gura.com.example.androidoracle;

import android.content.Context;

Expand All @@ -21,6 +21,6 @@ public class ExampleInstrumentedTest {
public void useAppContext() {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
assertEquals("ua.gura.com.example.andriodoracle", appContext.getPackageName());
assertEquals("ua.gura.com.example.androidoracle", appContext.getPackageName());
}
}
15 changes: 12 additions & 3 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,21 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="ua.gura.com.example.andriodoracle">
package="ua.gura.com.example.androidoracle">
<uses-permission android:name="android.permission.INTERNET"/>

<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.AndriodOracle">
<activity android:name=".MainActivity">
android:theme="@style/Theme.AndroidOracle"
android:name=".activities.App">

<activity android:name=".activities.main.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".activities.main.BaseActivity"
android:label="BaseActivity" />
<activity
android:name=".activities.details.DetailsActivity"
android:label="DetailsActivity" />
</application>

</manifest>

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package ua.gura.com.example.androidoracle.activities;

import android.app.Application;

import androidx.lifecycle.ViewModelProvider;
import androidx.room.Room;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import okhttp3.OkHttpClient;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
import ua.gura.com.example.androidoracle.activities.logger.AndroidLogger;
import ua.gura.com.example.androidoracle.activities.logger.Logger;
import ua.gura.com.example.androidoracle.activities.model.DateNagerService;
import ua.gura.com.example.androidoracle.activities.model.db.AppDB;
import ua.gura.com.example.androidoracle.activities.model.db.HolidayDAO;
import ua.gura.com.example.androidoracle.activities.model.db.HolidayDB;
import ua.gura.com.example.androidoracle.activities.model.network.DateNagerApi;

public class App extends Application {

private ViewModelProvider.Factory factory;
private static final String BASE_URL = "https://date.nager.at/";

@Override
public void onCreate() {
super.onCreate();
Logger logger = new AndroidLogger();
OkHttpClient httpClient = new OkHttpClient.Builder()
.addNetworkInterceptor(new HttpLoggingInterceptor()
.setLevel(HttpLoggingInterceptor.Level.BODY))
.build();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.client(httpClient)
.addConverterFactory(GsonConverterFactory.create())
.build();

DateNagerApi dateNagerApi = retrofit.create(DateNagerApi.class);
ExecutorService executorService = Executors.newCachedThreadPool();

AppDB appDB = Room.databaseBuilder(this, AppDB.class, "database.db")
.build();
HolidayDAO holidayDAO = appDB.getHolidayDAO();
DateNagerService dateNagerService = new DateNagerService(dateNagerApi, holidayDAO, executorService, logger);
factory = new ViewModelFactory(dateNagerService);
}

public ViewModelProvider.Factory getViewModelFactory() {
return factory;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package ua.gura.com.example.androidoracle.activities;

import androidx.lifecycle.ViewModel;

import ua.gura.com.example.androidoracle.activities.model.DateNagerService;

public class BaseViewModel extends ViewModel {
private DateNagerService dateNagerService;

public BaseViewModel(DateNagerService dateNagerService) {
this.dateNagerService = dateNagerService;
}

protected DateNagerService getDateNagerService() {
return dateNagerService;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package ua.gura.com.example.androidoracle.activities;

import android.util.Log;

import androidx.annotation.NonNull;
import androidx.lifecycle.ViewModel;
import androidx.lifecycle.ViewModelProvider;

import java.lang.reflect.Constructor;

import ua.gura.com.example.androidoracle.activities.model.DateNagerService;

public class ViewModelFactory implements ViewModelProvider.Factory {
public static final String TAG = ViewModelFactory.class.getSimpleName();
private DateNagerService dateNagerService;

public ViewModelFactory(DateNagerService dateNagerService) {
this.dateNagerService = dateNagerService;
}

@NonNull
@Override
public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
Constructor<T> constructor = null;
try {
constructor = modelClass.getConstructor(DateNagerService.class);
return constructor.newInstance(dateNagerService);
} catch (ReflectiveOperationException e) {
Log.e(TAG,"Error",e);
RuntimeException exception = new RuntimeException();
exception.initCause(e);
throw exception;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package ua.gura.com.example.androidoracle.activities.details;

import android.os.Bundle;
import android.widget.TextView;

import ua.gura.com.example.androidoracle.R;
import ua.gura.com.example.androidoracle.activities.App;
import ua.gura.com.example.androidoracle.activities.main.BaseActivity;
import ua.gura.com.example.androidoracle.activities.model.Holiday;

import androidx.lifecycle.ViewModelProvider;

public class DetailsActivity extends BaseActivity {

public static final String EXTRA_HOLIDAY_NAME = "HOLIDAY_NAME";
public static final String EXTRA_HOLIDAY_COUNTY_CODE = "HOLIDAY_COUNTY_CODE";
public static final String EXTRA_HOLIDAY_DATE = "HOLIDAY_DATE";
public static final String EXTRA_HOLIDAY_LAUNCH_YEAR = "HOLIDAY_LAUNCH_YEAR";

private TextView nameTextView;
private TextView dateTextView;
private TextView launchYearTextView;
private TextView countryCodeTextView;

private DetailsViewModel detailsViewModel;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_details);

nameTextView = findViewById(R.id.nameTextView);
dateTextView = findViewById(R.id.dateTextView);
launchYearTextView = findViewById(R.id.launchYearTextView);
countryCodeTextView = findViewById(R.id.countryCodeTextView);

String holidayName = getIntent().getStringExtra(EXTRA_HOLIDAY_NAME);
String holidayCountryCode = getIntent().getStringExtra(EXTRA_HOLIDAY_COUNTY_CODE);
String holidayDate = getIntent().getStringExtra(EXTRA_HOLIDAY_DATE);
int holidayLaunchYear = getIntent().getExtras().getInt(EXTRA_HOLIDAY_LAUNCH_YEAR);

if (holidayName.isEmpty() && holidayCountryCode.isEmpty() && holidayDate.isEmpty()) {
throw new RuntimeException("There is holiday haven`t name...");
}
nameTextView.setText(holidayName);
dateTextView.setText(holidayDate);
countryCodeTextView.setText(holidayCountryCode);
launchYearTextView.setText(holidayLaunchYear == 0 ? "Unknown" : String.valueOf(holidayLaunchYear));

App app = (App) getApplication();
ViewModelProvider viewModelProvider = new ViewModelProvider(this, app.getViewModelFactory());
detailsViewModel = viewModelProvider.get(DetailsViewModel.class);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package ua.gura.com.example.androidoracle.activities.details;

import ua.gura.com.example.androidoracle.activities.BaseViewModel;
import ua.gura.com.example.androidoracle.activities.model.DateNagerService;

public class DetailsViewModel extends BaseViewModel {
public DetailsViewModel(DateNagerService dateNagerService) {
super(dateNagerService);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package ua.gura.com.example.androidoracle.activities.logger;

import android.util.Log;

public class AndroidLogger implements Logger{
public static final String TAG = AndroidLogger.class.getSimpleName();

@Override
public void e(Throwable e) {
Log.e(TAG,"Error", e);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package ua.gura.com.example.androidoracle.activities.logger;

public interface Logger {
void e(Throwable e);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package ua.gura.com.example.androidoracle.activities.main;

import androidx.appcompat.app.AppCompatActivity;

public class BaseActivity extends AppCompatActivity {
public void cancel() {
finish();
}
}
Loading