├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── sshahini │ │ └── constraintsampleweather │ │ └── ApplicationTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── sshahini │ │ │ └── constraintsampleweather │ │ │ ├── adapters │ │ │ └── ForecastsAdapter.java │ │ │ ├── api │ │ │ ├── ApiRequest.java │ │ │ ├── CurrentWeatherInfoRequest.java │ │ │ ├── ForecastWeatherDataRequest.java │ │ │ ├── RequestQueue.java │ │ │ └── WeatherInfoApiRequest.java │ │ │ ├── controllers │ │ │ └── LocationController.java │ │ │ ├── events │ │ │ ├── BaseWeatherInfoEvent.java │ │ │ ├── CityNameChanged.java │ │ │ ├── CurrentWeatherInfoEvent.java │ │ │ ├── ForecastWeatherInfoEvent.java │ │ │ ├── LocationChangedEvent.java │ │ │ └── OnLocationPermissionDeniedEvent.java │ │ │ ├── models │ │ │ └── WeatherInfo.java │ │ │ ├── utils │ │ │ └── WeatherIconParser.java │ │ │ └── views │ │ │ ├── activities │ │ │ ├── BaseActivity.java │ │ │ └── MainActivity.java │ │ │ └── dialogs │ │ │ └── LocationChangerDialog.java │ └── res │ │ ├── drawable-v21 │ │ ├── ic_add_location_black_24dp.xml │ │ ├── ic_build_black_24dp.xml │ │ ├── ic_clearsky.xml │ │ ├── ic_cloudy.xml │ │ ├── ic_edit_location_black_24dp.xml │ │ ├── ic_fewclouds.xml │ │ ├── ic_forecast.xml │ │ ├── ic_home_black_24dp.xml │ │ ├── ic_humidity_black_24dp.xml │ │ ├── ic_info_black_24dp.xml │ │ ├── ic_mist.xml │ │ ├── ic_rain.xml │ │ ├── ic_receipt_black_24dp.xml │ │ ├── ic_replay_5_black_24dp.xml │ │ ├── ic_shower_rain.xml │ │ ├── ic_snow.xml │ │ ├── ic_thunderstorm.xml │ │ ├── ic_toys_black_24dp.xml │ │ ├── ic_wallpaper_60dp.xml │ │ └── ic_wind.xml │ │ ├── drawable-xxxhdpi │ │ ├── ic_thermometer.png │ │ ├── ic_thermometer_png.png │ │ ├── ic_wind_png.png │ │ └── img_city_downtown.png │ │ ├── drawable │ │ ├── selector_material_button.xml │ │ └── side_nav_bar.xml │ │ ├── layout │ │ ├── activity_main.xml │ │ ├── dialog_change_location.xml │ │ ├── layout_abstract_weather.xml │ │ ├── layout_content_main_activity.xml │ │ ├── layout_main_activity_header.xml │ │ └── layout_navigation_header.xml │ │ ├── menu │ │ └── menu_navigation.xml │ │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxxhdpi │ │ └── ic_launcher.png │ │ ├── values-v21 │ │ └── styles.xml │ │ ├── values-w820dp │ │ └── dimens.xml │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── drawables.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── sshahini │ └── constraintsampleweather │ └── ExampleUnitTest.java ├── build.gradle ├── device-2016-11-19-141343.png ├── device-2016-11-19-141408.png ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /README.md: -------------------------------------------------------------------------------- 1 | # ConstraintLayoutSample 2 | This is a sample that demonstrate usage of constraint layout and combine it with material design views. constraint layout is recently released android view by google that can falatten your view hierarchy. using constraint layout can reduce views draw time in complex UIs. 3 | 4 | 5 | 6 | 7 | ##Author 8 | Saeed shahini 9 | 10 | Saeedshahiniit@gmail.com 11 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 24 5 | buildToolsVersion "24.0.1" 6 | 7 | defaultConfig { 8 | applicationId "com.sshahini.constraintsampleweather" 9 | minSdkVersion 17 10 | targetSdkVersion 24 11 | versionCode 1 12 | versionName "1.0" 13 | vectorDrawables.useSupportLibrary=true 14 | } 15 | buildTypes { 16 | release { 17 | minifyEnabled false 18 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 19 | } 20 | } 21 | } 22 | 23 | dependencies { 24 | compile fileTree(include: ['*.jar'], dir: 'libs') 25 | testCompile 'junit:junit:4.12' 26 | compile 'com.android.support:appcompat-v7:24.2.0' 27 | compile 'com.android.support:design:24.2.0' 28 | compile 'com.android.volley:volley:1.0.0' 29 | compile 'com.squareup.picasso:picasso:2.5.2' 30 | compile 'com.android.support:cardview-v7:24.2.0' 31 | compile 'org.greenrobot:eventbus:3.0.0' 32 | compile 'com.android.support.constraint:constraint-layout:1.0.0-alpha8' 33 | } 34 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /home/saeed/android-sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/sshahini/constraintsampleweather/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.sshahini.constraintsampleweather; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /app/src/main/java/com/sshahini/constraintsampleweather/adapters/ForecastsAdapter.java: -------------------------------------------------------------------------------- 1 | package com.sshahini.constraintsampleweather.adapters; 2 | 3 | import android.content.Context; 4 | import android.support.graphics.drawable.VectorDrawableCompat; 5 | import android.support.v4.content.ContextCompat; 6 | import android.support.v7.widget.RecyclerView; 7 | import android.view.LayoutInflater; 8 | import android.view.View; 9 | import android.view.ViewGroup; 10 | import android.widget.ImageView; 11 | import android.widget.TextView; 12 | 13 | import com.sshahini.constraintsampleweather.R; 14 | import com.sshahini.constraintsampleweather.models.WeatherInfo; 15 | import com.sshahini.constraintsampleweather.utils.WeatherIconParser; 16 | 17 | import java.util.List; 18 | 19 | /** 20 | * Created by saeed on 7/16/16. 21 | */ 22 | public class ForecastsAdapter extends RecyclerView.Adapter{ 23 | 24 | private Context context; 25 | private List weatherInfos; 26 | private WeatherIconParser weatherIconParser; 27 | public ForecastsAdapter(Context context, List weatherInfos){ 28 | this.context=context; 29 | this.weatherInfos=weatherInfos; 30 | this.weatherIconParser =new WeatherIconParser(context); 31 | } 32 | @Override 33 | public ForecastViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 34 | return new ForecastViewHolder(LayoutInflater.from(context).inflate(R.layout.layout_abstract_weather,parent,false)); 35 | } 36 | 37 | @Override 38 | public void onBindViewHolder(ForecastViewHolder holder, int position) { 39 | WeatherInfo weatherInfo=weatherInfos.get(position); 40 | holder.minTempTextView.setText(String.valueOf(weatherInfo.getMinTemp())+WeatherInfo.TEMPERATURE_CELSIUS); 41 | holder.maxTempTextView.setText(String.valueOf(weatherInfo.getMaxTemp())+WeatherInfo.TEMPERATURE_CELSIUS); 42 | holder.dayNameTextView.setText(weatherInfo.getDate()); 43 | VectorDrawableCompat weatherIcon=weatherIconParser.getIcon(weatherInfo.getId()); 44 | weatherIcon.setTint(ContextCompat.getColor(context,R.color.colorAccent)); 45 | holder.weatherImageView.setImageDrawable(weatherIcon); 46 | } 47 | 48 | @Override 49 | public int getItemCount() { 50 | return weatherInfos.size() ; 51 | } 52 | 53 | public static class ForecastViewHolder extends RecyclerView.ViewHolder{ 54 | private TextView minTempTextView; 55 | private TextView maxTempTextView; 56 | private TextView dayNameTextView; 57 | private ImageView weatherImageView; 58 | public ForecastViewHolder(View itemView) { 59 | super(itemView); 60 | minTempTextView=(TextView)itemView.findViewById(R.id.historical_weather_min_temp); 61 | maxTempTextView=(TextView)itemView.findViewById(R.id.historical_weather_max_temp); 62 | dayNameTextView=(TextView)itemView.findViewById(R.id.histrocal_weather_day_name); 63 | weatherImageView=(ImageView)itemView.findViewById(R.id.historical_weather_icon); 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /app/src/main/java/com/sshahini/constraintsampleweather/api/ApiRequest.java: -------------------------------------------------------------------------------- 1 | package com.sshahini.constraintsampleweather.api; 2 | 3 | import android.content.Context; 4 | 5 | import com.android.volley.DefaultRetryPolicy; 6 | import com.android.volley.Request; 7 | 8 | /** 9 | * Created by saeed on 7/13/16. 10 | */ 11 | public class ApiRequest { 12 | protected static final int TIME_OUT=15000; 13 | protected static final String OPEN_WEATHER_MAP_API_KEY="0067ea3ffc9cad0548529afa3639f76f"; 14 | protected Context context; 15 | public ApiRequest(Context context){ 16 | this.context=context; 17 | } 18 | protected void setRetryPolicy(Request request,int timeOut,int maxRetries,int backoffMultiplier){ 19 | request.setRetryPolicy(new DefaultRetryPolicy(timeOut,maxRetries,backoffMultiplier)); 20 | } 21 | protected void setDefaultRetrtyPolicy(Request request){ 22 | request.setRetryPolicy(new DefaultRetryPolicy(TIME_OUT,DefaultRetryPolicy.DEFAULT_MAX_RETRIES,DefaultRetryPolicy.DEFAULT_BACKOFF_MULT)); 23 | } 24 | protected void addToQueue(Request request){ 25 | RequestQueue.getInstance(context).addToRequestQueue(request); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /app/src/main/java/com/sshahini/constraintsampleweather/api/CurrentWeatherInfoRequest.java: -------------------------------------------------------------------------------- 1 | package com.sshahini.constraintsampleweather.api; 2 | 3 | import android.content.Context; 4 | import android.util.Log; 5 | 6 | import com.android.volley.Request; 7 | import com.android.volley.Response; 8 | import com.android.volley.VolleyError; 9 | import com.android.volley.toolbox.JsonObjectRequest; 10 | import com.sshahini.constraintsampleweather.events.CurrentWeatherInfoEvent; 11 | import com.sshahini.constraintsampleweather.models.WeatherInfo; 12 | 13 | import org.greenrobot.eventbus.EventBus; 14 | import org.json.JSONException; 15 | import org.json.JSONObject; 16 | 17 | /** 18 | * Created by saeed on 7/13/16. 19 | */ 20 | public class CurrentWeatherInfoRequest extends WeatherInfoApiRequest { 21 | private static final String TAG = "CurrentWeather"; 22 | 23 | public CurrentWeatherInfoRequest(Context context) { 24 | super(context); 25 | } 26 | 27 | 28 | @Override 29 | public void sendRequest(final double latitude, final double longitude) { 30 | Log.d(TAG, "getWeather() called with: " + "latitude = [" + latitude + "], longitude = [" + longitude + "]"); 31 | send(getApiUrl(latitude, longitude)); 32 | } 33 | 34 | @Override 35 | public void sendRequest(String cityName) { 36 | Log.d(TAG, "sendRequest() called with: " + "cityName = [" + cityName + "]"); 37 | send(getApiUrl(cityName)); 38 | } 39 | 40 | private void send(String apiUrl) { 41 | JsonObjectRequest request = new JsonObjectRequest(Request.Method.GET, apiUrl, null, new Response.Listener() { 42 | @Override 43 | public void onResponse(JSONObject response) { 44 | try { 45 | WeatherInfo weatherInfo = WeatherInfo.parseWeatherInfoApiResponse(response); 46 | EventBus.getDefault().post(new CurrentWeatherInfoEvent(weatherInfo, null)); 47 | } catch (JSONException e) { 48 | EventBus.getDefault().post(new CurrentWeatherInfoEvent(null, e)); 49 | Log.e(TAG, "onResponse: " + e.toString()); 50 | } 51 | } 52 | }, new Response.ErrorListener() { 53 | @Override 54 | public void onErrorResponse(VolleyError error) { 55 | EventBus.getDefault().post(new CurrentWeatherInfoEvent(null, error)); 56 | Log.e(TAG, "onErrorResponse: " + error.toString()); 57 | } 58 | }); 59 | setDefaultRetrtyPolicy(request); 60 | addToQueue(request); 61 | } 62 | 63 | private String getApiUrl(double latitude, double longitude) { 64 | return "http://api.openweathermap.org/data/2.5/weather?lat=" + latitude + "&lon=" + longitude + "&mode=json&cnt=10" + "&APPID=" + ApiRequest.OPEN_WEATHER_MAP_API_KEY; 65 | } 66 | 67 | private String getApiUrl(String cityName) { 68 | return "http://api.openweathermap.org/data/2.5/weather?q=" + cityName + "&mode=json&cnt=10" + "&APPID=" + ApiRequest.OPEN_WEATHER_MAP_API_KEY; 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /app/src/main/java/com/sshahini/constraintsampleweather/api/ForecastWeatherDataRequest.java: -------------------------------------------------------------------------------- 1 | package com.sshahini.constraintsampleweather.api; 2 | 3 | import android.content.Context; 4 | import android.util.Log; 5 | 6 | import com.android.volley.Request; 7 | import com.android.volley.Response; 8 | import com.android.volley.VolleyError; 9 | import com.android.volley.toolbox.JsonObjectRequest; 10 | import com.sshahini.constraintsampleweather.events.CurrentWeatherInfoEvent; 11 | import com.sshahini.constraintsampleweather.events.ForecastWeatherInfoEvent; 12 | import com.sshahini.constraintsampleweather.models.WeatherInfo; 13 | 14 | import org.greenrobot.eventbus.EventBus; 15 | import org.json.JSONException; 16 | import org.json.JSONObject; 17 | 18 | import java.util.List; 19 | 20 | /** 21 | * Created by saeed on 7/13/16. 22 | */ 23 | public class ForecastWeatherDataRequest extends WeatherInfoApiRequest { 24 | private static final String TAG = "HistoricalWeather"; 25 | public ForecastWeatherDataRequest(Context context){ 26 | super(context); 27 | } 28 | 29 | @Override 30 | public void sendRequest(double latitude, double longitude) { 31 | Log.d(TAG, "getWeather() called with: " + "latitude = [" + latitude + "], longitude = [" + longitude + "]"); 32 | send(getApiUrl(latitude,longitude)); 33 | } 34 | 35 | @Override 36 | public void sendRequest(String cityName) { 37 | Log.d(TAG, "sendRequest() called with: " + "cityName = [" + cityName + "]"); 38 | send(getApiUrl(cityName)); 39 | } 40 | private void send(String apiUrl){ 41 | JsonObjectRequest request=new JsonObjectRequest(Request.Method.GET, apiUrl, null, new Response.Listener() { 42 | @Override 43 | public void onResponse(JSONObject response) { 44 | Log.d(TAG, "onResponse() called with: " + "response = [" + response + "]"); 45 | try { 46 | List weatherInfos=WeatherInfo.parseForecastApiResponse(response); 47 | EventBus.getDefault().post(new ForecastWeatherInfoEvent(weatherInfos,null)); 48 | } catch (JSONException e) { 49 | EventBus.getDefault().post(new ForecastWeatherInfoEvent(null,e)); 50 | } 51 | } 52 | }, new Response.ErrorListener() { 53 | @Override 54 | public void onErrorResponse(VolleyError error) { 55 | EventBus.getDefault().post(new CurrentWeatherInfoEvent(null,error)); 56 | Log.e(TAG, "onErrorResponse: "+error.toString() ); 57 | 58 | } 59 | }); 60 | setDefaultRetrtyPolicy(request); 61 | addToQueue(request); 62 | } 63 | 64 | private String getApiUrl(double latitude, double longitude){ 65 | return "http://api.openweathermap.org/data/2.5/forecast/daily?lat=" + latitude + "&lon="+ longitude+"&type=hour"+"&APPID="+ ApiRequest.OPEN_WEATHER_MAP_API_KEY; 66 | } 67 | private String getApiUrl(String cityName){ 68 | return "http://api.openweathermap.org/data/2.5/forecast/daily?q=" + cityName +"&type=hour"+"&APPID="+ ApiRequest.OPEN_WEATHER_MAP_API_KEY; 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /app/src/main/java/com/sshahini/constraintsampleweather/api/RequestQueue.java: -------------------------------------------------------------------------------- 1 | package com.sshahini.constraintsampleweather.api; 2 | 3 | import android.content.Context; 4 | import android.util.Log; 5 | 6 | import com.android.volley.Request; 7 | import com.android.volley.toolbox.Volley; 8 | 9 | /** 10 | * Created by saeed on 7/13/16. 11 | */ 12 | 13 | public class RequestQueue { 14 | 15 | private static RequestQueue _inst; 16 | private Context _context; 17 | private com.android.volley.RequestQueue _requestQueue; 18 | 19 | 20 | public RequestQueue(Context context) {//Instructor 21 | this._context = context; 22 | getRequestQueue(); 23 | } 24 | 25 | public static synchronized RequestQueue getInstance(Context context) {// get a new instance of class 26 | if (_inst == null) { 27 | _inst = new RequestQueue(context); 28 | } 29 | return _inst; 30 | } 31 | 32 | public void addToRequestQueue(Request request) {// add request to queue 33 | getRequestQueue().add(request); 34 | } 35 | 36 | 37 | public void addToRequestQueue(Request request,String tag) {// add request to queue 38 | getRequestQueue().add(request).setTag(tag); 39 | } 40 | 41 | private com.android.volley.RequestQueue getRequestQueue() { 42 | if (_requestQueue == null) { 43 | _requestQueue = Volley.newRequestQueue(_context); 44 | } 45 | return _requestQueue; 46 | } 47 | public void clearRequestQueue(){ 48 | _requestQueue.cancelAll(new com.android.volley.RequestQueue.RequestFilter() { 49 | @Override 50 | public boolean apply(Request request) { 51 | return true; 52 | } 53 | }); 54 | Log.i("Request","all http requests was canceled, context: "+_context.toString()); 55 | } 56 | public void cancelRequest(String tag){ 57 | _requestQueue.cancelAll(tag); 58 | Log.i("Request", "cancelRequest: all request with tag "+tag+" are canceled"); 59 | } 60 | 61 | } 62 | 63 | -------------------------------------------------------------------------------- /app/src/main/java/com/sshahini/constraintsampleweather/api/WeatherInfoApiRequest.java: -------------------------------------------------------------------------------- 1 | package com.sshahini.constraintsampleweather.api; 2 | 3 | import android.content.Context; 4 | 5 | /** 6 | * Created by saeed on 7/13/16. 7 | */ 8 | public abstract class WeatherInfoApiRequest extends ApiRequest{ 9 | 10 | 11 | 12 | public WeatherInfoApiRequest(Context context){ 13 | super(context); 14 | } 15 | 16 | public abstract void sendRequest(double latitude, double longitude); 17 | public abstract void sendRequest(String cityName); 18 | 19 | } 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/java/com/sshahini/constraintsampleweather/controllers/LocationController.java: -------------------------------------------------------------------------------- 1 | package com.sshahini.constraintsampleweather.controllers; 2 | 3 | import android.Manifest; 4 | import android.content.Context; 5 | import android.content.pm.PackageManager; 6 | import android.location.Location; 7 | import android.location.LocationListener; 8 | import android.location.LocationManager; 9 | import android.os.Build; 10 | import android.os.Bundle; 11 | import android.support.annotation.Nullable; 12 | import android.support.design.widget.Snackbar; 13 | import android.support.v4.app.ActivityCompat; 14 | import android.support.v7.app.AppCompatActivity; 15 | import android.util.Log; 16 | import android.widget.Toast; 17 | 18 | import com.sshahini.constraintsampleweather.events.LocationChangedEvent; 19 | import com.sshahini.constraintsampleweather.events.OnLocationPermissionDeniedEvent; 20 | 21 | import org.greenrobot.eventbus.EventBus; 22 | 23 | /** 24 | * Created by saeed on 7/12/16. 25 | */ 26 | public class LocationController implements LocationListener { 27 | 28 | private static final String TAG = "LocationController"; 29 | 30 | private Context context; 31 | private LocationManager locationManager; 32 | private static final long MIN_TIME_FOR_UPDATE = 10000; 33 | private static final long MIN_DISTANCE_UPDATE = 1000; 34 | public static final int LOCATION_PERMISSION_REQUEST_CODE=999; 35 | 36 | public LocationController(Context context) { 37 | this.context = context; 38 | if (Build.VERSION.SDK_INT>=23) { 39 | if (ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && 40 | ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { 41 | Log.e(TAG, "LocationController: location permission denied!!!"); 42 | ((AppCompatActivity) context).requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION,Manifest.permission.ACCESS_COARSE_LOCATION}, 43 | LOCATION_PERMISSION_REQUEST_CODE); 44 | return; 45 | } 46 | } 47 | this.locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE); 48 | this.locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, MIN_TIME_FOR_UPDATE, MIN_DISTANCE_UPDATE, this); 49 | 50 | } 51 | 52 | public Location getCurrentLocation() { 53 | Location gpsLocation = getLocationProvider(LocationManager.GPS_PROVIDER); 54 | if (gpsLocation == null) { 55 | return getLocationProvider(LocationManager.NETWORK_PROVIDER);//return network location 56 | } else { 57 | return gpsLocation;//return gps location 58 | } 59 | } 60 | 61 | @Nullable 62 | public Location getLocationProvider(String provider) { 63 | Location location = null; 64 | if (locationManager != null) { 65 | if (locationManager.isProviderEnabled(provider)) { 66 | if (ActivityCompat.checkSelfPermission(context, 67 | Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { 68 | Toast.makeText(context, "You are not granted location service permission", Toast.LENGTH_LONG).show(); 69 | return null; 70 | } 71 | location = locationManager.getLastKnownLocation(provider); 72 | } 73 | } else { 74 | EventBus.getDefault().post(new OnLocationPermissionDeniedEvent()); 75 | } 76 | return location; 77 | } 78 | 79 | @Override 80 | public void onLocationChanged(Location location) { 81 | Log.d(TAG, "onLocationChangedEvent() called with: " + "location = [" + location + "]"); 82 | EventBus.getDefault().post(new LocationChangedEvent(location.getLatitude(), location.getLongitude())); 83 | } 84 | 85 | @Override 86 | public void onStatusChanged(String provider, int status, Bundle extras) { 87 | 88 | } 89 | 90 | @Override 91 | public void onProviderEnabled(String provider) { 92 | 93 | } 94 | 95 | @Override 96 | public void onProviderDisabled(String provider) { 97 | 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /app/src/main/java/com/sshahini/constraintsampleweather/events/BaseWeatherInfoEvent.java: -------------------------------------------------------------------------------- 1 | package com.sshahini.constraintsampleweather.events; 2 | 3 | /** 4 | * Created by saeed on 7/16/16. 5 | */ 6 | public class BaseWeatherInfoEvent { 7 | private Exception exception; 8 | 9 | 10 | public BaseWeatherInfoEvent(Exception exception){ 11 | this.exception=exception; 12 | } 13 | 14 | public Exception getException() { 15 | return exception; 16 | } 17 | 18 | public void setException(Exception exception) { 19 | this.exception = exception; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /app/src/main/java/com/sshahini/constraintsampleweather/events/CityNameChanged.java: -------------------------------------------------------------------------------- 1 | package com.sshahini.constraintsampleweather.events; 2 | 3 | /** 4 | * Created by saeed on 7/16/16. 5 | */ 6 | public class CityNameChanged { 7 | private String newCityName; 8 | public CityNameChanged(String newcityName){ 9 | this.newCityName=newcityName; 10 | } 11 | 12 | public String getNewCityName() { 13 | return newCityName; 14 | } 15 | 16 | public void setNewCityName(String newCityName) { 17 | this.newCityName = newCityName; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /app/src/main/java/com/sshahini/constraintsampleweather/events/CurrentWeatherInfoEvent.java: -------------------------------------------------------------------------------- 1 | package com.sshahini.constraintsampleweather.events; 2 | 3 | import com.sshahini.constraintsampleweather.models.WeatherInfo; 4 | 5 | /** 6 | * Created by saeed on 7/16/16. 7 | */ 8 | public class CurrentWeatherInfoEvent extends BaseWeatherInfoEvent { 9 | private WeatherInfo weatherInfo; 10 | 11 | public CurrentWeatherInfoEvent(WeatherInfo weatherInfo,Exception exception) { 12 | super(exception); 13 | this.weatherInfo=weatherInfo; 14 | } 15 | 16 | public WeatherInfo getWeatherInfo() { 17 | return weatherInfo; 18 | } 19 | 20 | public void setWeatherInfo(WeatherInfo weatherInfo) { 21 | this.weatherInfo = weatherInfo; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /app/src/main/java/com/sshahini/constraintsampleweather/events/ForecastWeatherInfoEvent.java: -------------------------------------------------------------------------------- 1 | package com.sshahini.constraintsampleweather.events; 2 | 3 | import com.sshahini.constraintsampleweather.models.WeatherInfo; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * Created by saeed on 7/16/16. 9 | */ 10 | public class ForecastWeatherInfoEvent extends BaseWeatherInfoEvent { 11 | private int id=0; 12 | private List weatherInfo; 13 | 14 | public ForecastWeatherInfoEvent(List weatherInfo, Exception exception) { 15 | super(exception); 16 | this.weatherInfo=weatherInfo; 17 | } 18 | 19 | public int getId() { 20 | return id; 21 | } 22 | 23 | public void setId(int id) { 24 | this.id = id; 25 | } 26 | 27 | public List getWeatherInfo() { 28 | return weatherInfo; 29 | } 30 | 31 | public void setWeatherInfo(List weatherInfo) { 32 | this.weatherInfo = weatherInfo; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /app/src/main/java/com/sshahini/constraintsampleweather/events/LocationChangedEvent.java: -------------------------------------------------------------------------------- 1 | package com.sshahini.constraintsampleweather.events; 2 | 3 | /** 4 | * Created by saeed on 7/16/16. 5 | */ 6 | public class LocationChangedEvent { 7 | private double latitude; 8 | private double longitude; 9 | 10 | public LocationChangedEvent(double latitude,double longitude){ 11 | this.latitude=latitude; 12 | this.longitude=longitude; 13 | } 14 | public double getLatitude() { 15 | return latitude; 16 | } 17 | 18 | public void setLatitude(double latitude) { 19 | this.latitude = latitude; 20 | } 21 | 22 | public double getLongitude() { 23 | return longitude; 24 | } 25 | 26 | public void setLongitude(double longitude) { 27 | this.longitude = longitude; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /app/src/main/java/com/sshahini/constraintsampleweather/events/OnLocationPermissionDeniedEvent.java: -------------------------------------------------------------------------------- 1 | package com.sshahini.constraintsampleweather.events; 2 | 3 | /** 4 | * @author S.Shahini 5 | * @since 10/4/16 6 | */ 7 | 8 | public class OnLocationPermissionDeniedEvent { 9 | public static final String MESSAGE="You don't permitted access to location manager"; 10 | } 11 | -------------------------------------------------------------------------------- /app/src/main/java/com/sshahini/constraintsampleweather/models/WeatherInfo.java: -------------------------------------------------------------------------------- 1 | package com.sshahini.constraintsampleweather.models; 2 | 3 | import android.support.annotation.Nullable; 4 | import android.util.Log; 5 | 6 | import org.json.JSONArray; 7 | import org.json.JSONException; 8 | import org.json.JSONObject; 9 | 10 | import java.text.DecimalFormat; 11 | import java.text.SimpleDateFormat; 12 | import java.util.ArrayList; 13 | import java.util.Date; 14 | import java.util.List; 15 | 16 | /** 17 | * Created by saeed on 7/12/16. 18 | */ 19 | public class WeatherInfo { 20 | private static final String TAG = "WeatherInfo"; 21 | 22 | //Units of measurement strings for ui 23 | public static final String TEMPERATURE_CELSIUS = "\u00B0"; 24 | private static final String KM = "KM"; 25 | 26 | private int id; 27 | private String state; 28 | private String description; 29 | private String base; 30 | private float windSpeed; 31 | private int humidity; 32 | private int minTemp; 33 | private int maxTemp; 34 | private float temperature; 35 | private String city; 36 | private String date; 37 | 38 | 39 | public int getId() { 40 | return id; 41 | } 42 | 43 | public void setId(int id) { 44 | this.id = id; 45 | } 46 | 47 | public String getState() { 48 | return state; 49 | } 50 | 51 | public void setState(String state) { 52 | this.state = state; 53 | } 54 | 55 | public String getDescription() { 56 | return description; 57 | } 58 | 59 | public void setDescription(String description) { 60 | this.description = description; 61 | } 62 | 63 | public String getBase() { 64 | return base; 65 | } 66 | 67 | public void setBase(String base) { 68 | this.base = base; 69 | } 70 | 71 | public float getWindSpeed() { 72 | return windSpeed; 73 | } 74 | 75 | public void setWindSpeed(float windSpeed) { 76 | this.windSpeed = windSpeed; 77 | } 78 | 79 | public int getHumidity() { 80 | return humidity; 81 | } 82 | 83 | public void setHumidity(int humidity) { 84 | this.humidity = humidity; 85 | } 86 | 87 | public int getMinTemp() { 88 | return minTemp; 89 | } 90 | 91 | public void setMinTemp(int minTemp) { 92 | minTemp-=273.15; 93 | this.minTemp = minTemp; 94 | } 95 | 96 | public int getMaxTemp() { 97 | return maxTemp; 98 | } 99 | 100 | public void setMaxTemp(int maxTemp) { 101 | maxTemp-=273.15; 102 | this.maxTemp = maxTemp; 103 | } 104 | 105 | public String getCity() { 106 | return city; 107 | } 108 | 109 | public void setCity(String city) { 110 | this.city = city; 111 | } 112 | 113 | public String getMinMaxTempUiText() { 114 | return minTemp + TEMPERATURE_CELSIUS + " " + maxTemp + TEMPERATURE_CELSIUS; 115 | } 116 | 117 | public String getWindSpeedUiText() { 118 | return windSpeed + " " + KM; 119 | } 120 | 121 | public String getHumidityUiText() { 122 | return humidity + " %"; 123 | } 124 | 125 | 126 | public String getCurrentTempUiText() { 127 | DecimalFormat decimalFormat=new DecimalFormat("#.##"); 128 | 129 | return decimalFormat.format(temperature) + TEMPERATURE_CELSIUS; 130 | } 131 | 132 | public float getTemperature() { 133 | return temperature; 134 | } 135 | 136 | public void setTemperature(float temperature) { 137 | temperature-=273.15; 138 | this.temperature = temperature; 139 | } 140 | 141 | public String getDate() { 142 | return date; 143 | } 144 | 145 | public void setDate(String date) { 146 | this.date = date; 147 | } 148 | 149 | @Nullable 150 | public static WeatherInfo parseWeatherInfoApiResponse(JSONObject jsonObject) throws JSONException { 151 | Log.d(TAG, "parseWeatherInfoApiResponse() called with: " + "jsonObject = [" + jsonObject + "]"); 152 | WeatherInfo weatherInfo = new WeatherInfo(); 153 | JSONObject weather = jsonObject.getJSONArray("weather").getJSONObject(0); 154 | weatherInfo.setId(weather.getInt("id")); 155 | weatherInfo.setState(weather.getString("main")); 156 | weatherInfo.setDescription(weather.getString("description")); 157 | 158 | // TODO: 7/13/16 change this 159 | weatherInfo.setCity(jsonObject.getString("name")); 160 | 161 | JSONObject main = jsonObject.getJSONObject("main"); 162 | weatherInfo.setHumidity(main.getInt("humidity")); 163 | weatherInfo.setMinTemp(main.getInt("temp_min")); 164 | weatherInfo.setMaxTemp(main.getInt("temp_max")); 165 | weatherInfo.setTemperature((float) main.getDouble("temp")); 166 | JSONObject wind = jsonObject.getJSONObject("wind"); 167 | weatherInfo.setWindSpeed((float) wind.getDouble("speed")); 168 | return weatherInfo; 169 | } 170 | 171 | @Nullable 172 | public static List parseForecastApiResponse(JSONObject response) throws JSONException { 173 | Log.d(TAG, "parseWeatherInfoApiResponse() called with: " + "jsonObject = [" + response + "]"); 174 | List weatherInfos = new ArrayList<>(); 175 | 176 | String city = response.getJSONObject("city").getString("name"); 177 | 178 | JSONArray weathersListJsonArray = response.getJSONArray("list"); 179 | for (int i = 0; i < weathersListJsonArray.length(); i++) { 180 | WeatherInfo weatherInfo = new WeatherInfo(); 181 | JSONObject weatherInfoJsonObject = weathersListJsonArray.getJSONObject(i); 182 | 183 | Log.i(TAG, "parseForecastApiResponse: date:" + weatherInfoJsonObject.getLong("dt")); 184 | weatherInfo.setDate(new SimpleDateFormat("EEEE").format(new Date(weatherInfoJsonObject.getLong("dt") * 1000))); 185 | weatherInfo.setMinTemp(weatherInfoJsonObject.getJSONObject("temp").getInt("min")); 186 | weatherInfo.setMaxTemp(weatherInfoJsonObject.getJSONObject("temp").getInt("max")); 187 | weatherInfo.setState(weatherInfoJsonObject.getJSONArray("weather").getJSONObject(0).getString("main")); 188 | weatherInfo.setId(weatherInfoJsonObject.getJSONArray("weather").getJSONObject(0).getInt("id")); 189 | weatherInfo.setCity(city); 190 | weatherInfos.add(weatherInfo); 191 | } 192 | 193 | return weatherInfos; 194 | } 195 | 196 | 197 | } 198 | -------------------------------------------------------------------------------- /app/src/main/java/com/sshahini/constraintsampleweather/utils/WeatherIconParser.java: -------------------------------------------------------------------------------- 1 | package com.sshahini.constraintsampleweather.utils; 2 | 3 | import android.content.Context; 4 | import android.support.graphics.drawable.VectorDrawableCompat; 5 | 6 | import com.sshahini.constraintsampleweather.R; 7 | 8 | /** 9 | * Created by saeed on 7/16/16. 10 | * this class get weather id and return appropriate drawable 11 | */ 12 | public class WeatherIconParser { 13 | private Context context; 14 | public WeatherIconParser(Context context){ 15 | this.context=context; 16 | } 17 | public VectorDrawableCompat getIcon(int weatherId){ 18 | 19 | String firstNumber=String.valueOf(weatherId).substring(0,1); 20 | switch (firstNumber){ 21 | case "2": 22 | return VectorDrawableCompat.create(context.getResources(), R.drawable.ic_thunderstorm,null); 23 | case "3": 24 | return VectorDrawableCompat.create(context.getResources(), R.drawable.ic_rain,null); 25 | case "5": 26 | return VectorDrawableCompat.create(context.getResources(), R.drawable.ic_shower_rain,null); 27 | case "6": 28 | return VectorDrawableCompat.create(context.getResources(), R.drawable.ic_snow,null); 29 | case "7": 30 | return VectorDrawableCompat.create(context.getResources(), R.drawable.ic_mist,null); 31 | case "8": 32 | if (weatherId==800) 33 | return VectorDrawableCompat.create(context.getResources(), R.drawable.ic_clearsky,null); 34 | else 35 | if (weatherId==801) 36 | return VectorDrawableCompat.create(context.getResources(), R.drawable.ic_fewclouds,null); 37 | else 38 | return VectorDrawableCompat.create(context.getResources(), R.drawable.ic_cloudy,null); 39 | case "9": 40 | return VectorDrawableCompat.create(context.getResources(), R.drawable.ic_wind,null); 41 | default: 42 | return VectorDrawableCompat.create(context.getResources(), R.drawable.ic_clearsky,null); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /app/src/main/java/com/sshahini/constraintsampleweather/views/activities/BaseActivity.java: -------------------------------------------------------------------------------- 1 | package com.sshahini.constraintsampleweather.views.activities; 2 | 3 | import android.support.v7.app.AppCompatActivity; 4 | 5 | import org.greenrobot.eventbus.EventBus; 6 | 7 | /** 8 | * Created by saeed on 7/16/16. 9 | */ 10 | public class BaseActivity extends AppCompatActivity{ 11 | @Override 12 | protected void onStart() { 13 | super.onStart(); 14 | EventBus.getDefault().register(this); 15 | } 16 | 17 | @Override 18 | protected void onStop() { 19 | super.onStop(); 20 | EventBus.getDefault().unregister(this); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /app/src/main/java/com/sshahini/constraintsampleweather/views/activities/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.sshahini.constraintsampleweather.views.activities; 2 | 3 | import android.content.pm.PackageManager; 4 | import android.location.Location; 5 | import android.support.annotation.NonNull; 6 | import android.support.design.widget.CollapsingToolbarLayout; 7 | import android.support.design.widget.CoordinatorLayout; 8 | import android.support.design.widget.FloatingActionButton; 9 | import android.support.design.widget.Snackbar; 10 | import android.support.graphics.drawable.VectorDrawableCompat; 11 | import android.support.v4.content.ContextCompat; 12 | import android.support.v4.widget.DrawerLayout; 13 | import android.support.v7.app.ActionBarDrawerToggle; 14 | import android.os.Bundle; 15 | import android.support.v7.widget.LinearLayoutManager; 16 | import android.support.v7.widget.RecyclerView; 17 | import android.support.v7.widget.Toolbar; 18 | import android.util.Log; 19 | import android.view.View; 20 | import android.widget.ImageView; 21 | import android.widget.ProgressBar; 22 | import android.widget.TextView; 23 | 24 | import com.sshahini.constraintsampleweather.controllers.LocationController; 25 | import com.sshahini.constraintsampleweather.R; 26 | import com.sshahini.constraintsampleweather.adapters.ForecastsAdapter; 27 | import com.sshahini.constraintsampleweather.api.CurrentWeatherInfoRequest; 28 | import com.sshahini.constraintsampleweather.api.ForecastWeatherDataRequest; 29 | import com.sshahini.constraintsampleweather.events.CityNameChanged; 30 | import com.sshahini.constraintsampleweather.events.CurrentWeatherInfoEvent; 31 | import com.sshahini.constraintsampleweather.events.ForecastWeatherInfoEvent; 32 | import com.sshahini.constraintsampleweather.events.LocationChangedEvent; 33 | import com.sshahini.constraintsampleweather.events.OnLocationPermissionDeniedEvent; 34 | import com.sshahini.constraintsampleweather.models.WeatherInfo; 35 | import com.sshahini.constraintsampleweather.utils.WeatherIconParser; 36 | import com.sshahini.constraintsampleweather.views.dialogs.LocationChangerDialog; 37 | 38 | import org.greenrobot.eventbus.Subscribe; 39 | import org.greenrobot.eventbus.ThreadMode; 40 | 41 | import java.util.ArrayList; 42 | import java.util.List; 43 | import java.util.jar.Manifest; 44 | 45 | public class MainActivity extends BaseActivity { 46 | private static final String TAG = "MainActivity"; 47 | // Primary views 48 | /////////////////////////////////////////////////////////////////////////// 49 | private Toolbar toolbar; 50 | private ProgressBar progressBar; 51 | private CoordinatorLayout coordinatorLayout; 52 | 53 | // Weather info related fields 54 | /////////////////////////////////////////////////////////////////////////// 55 | private TextView txtHumidity; 56 | private TextView txtMinMaxTemp; 57 | private TextView txtWindSpeed; 58 | private TextView txtCurrentTemp; 59 | private TextView txtCity; 60 | private TextView txtDescription; 61 | private ImageView currentWeatherIconImageView; 62 | private WeatherIconParser weatherIconParser; 63 | 64 | // Forecasts weather data 65 | /////////////////////////////////////////////////////////////////////////// 66 | private RecyclerView forecastsRecyclerView; 67 | private List forecasts = new ArrayList<>(); 68 | private ForecastsAdapter forecastsAdapter; 69 | 70 | private static final String STRING_DEFAULT_CITY="NewYork"; 71 | 72 | @Override 73 | protected void onCreate(Bundle savedInstanceState) { 74 | super.onCreate(savedInstanceState); 75 | setContentView(R.layout.activity_main); 76 | weatherIconParser = new WeatherIconParser(this); 77 | initViews(); 78 | if (getCurrentLocation() != null) { 79 | getWeather(getCurrentLocation()); 80 | getForecastData(getCurrentLocation()); 81 | }else { 82 | getWeather(STRING_DEFAULT_CITY); 83 | getForecastData(STRING_DEFAULT_CITY); 84 | } 85 | } 86 | 87 | private void initViews() { 88 | initToolbar(); 89 | initNavigationView(); 90 | initList(); 91 | progressBar = (ProgressBar) findViewById(R.id.progressbar); 92 | coordinatorLayout = (CoordinatorLayout) findViewById(R.id.coordinator_layout); 93 | 94 | txtHumidity = (TextView) findViewById(R.id.textview_humidity); 95 | txtMinMaxTemp = (TextView) findViewById(R.id.textview_min_max_temp); 96 | txtWindSpeed = (TextView) findViewById(R.id.textview_wind_speed); 97 | txtCurrentTemp = (TextView) findViewById(R.id.textview_current_temp); 98 | txtCity = (TextView) findViewById(R.id.textview_city); 99 | txtDescription = (TextView) findViewById(R.id.current_temp_desc); 100 | currentWeatherIconImageView = (ImageView) findViewById(R.id.current_temp_icon); 101 | FloatingActionButton btnChangeCityName = (FloatingActionButton) findViewById(R.id.change_city_name); 102 | 103 | btnChangeCityName.setOnClickListener(new View.OnClickListener() { 104 | @Override 105 | public void onClick(View v) { 106 | new LocationChangerDialog().show(getSupportFragmentManager(), null); 107 | } 108 | }); 109 | } 110 | 111 | private void initToolbar() { 112 | toolbar = (Toolbar) findViewById(R.id.toolbar); 113 | toolbar.setTitleTextColor(ContextCompat.getColor(this, android.R.color.white)); 114 | 115 | CollapsingToolbarLayout collapsingToolbarLayout = (CollapsingToolbarLayout) findViewById(R.id.collapsing_toolbar); 116 | collapsingToolbarLayout.setTitleEnabled(false); 117 | setSupportActionBar(toolbar); 118 | } 119 | 120 | private void initNavigationView() { 121 | DrawerLayout drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout); 122 | ActionBarDrawerToggle drawerToggle = new ActionBarDrawerToggle(this, drawerLayout, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close); 123 | drawerLayout.setDrawerListener(drawerToggle); 124 | drawerToggle.syncState(); 125 | } 126 | 127 | private void initList() { 128 | 129 | forecastsRecyclerView = (RecyclerView) findViewById(R.id.forecasts_list); 130 | forecastsRecyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)); 131 | forecastsAdapter = new ForecastsAdapter(this, forecasts); 132 | forecastsRecyclerView.setAdapter(forecastsAdapter); 133 | } 134 | 135 | @Override 136 | protected void onResume() { 137 | super.onResume(); 138 | } 139 | 140 | private Location getCurrentLocation() { 141 | LocationController locationController = new LocationController(this); 142 | return locationController.getCurrentLocation(); 143 | } 144 | 145 | private void getWeather(Location location) { 146 | if (location != null) { 147 | getWeather(location.getLatitude(), location.getLongitude()); 148 | } else { 149 | Log.w(TAG, "getWeather: Location is Null!!!"); 150 | } 151 | } 152 | 153 | private void getWeather(String cityName) { 154 | progressBar.setVisibility(View.VISIBLE); 155 | new CurrentWeatherInfoRequest(this).sendRequest(cityName); 156 | } 157 | 158 | private void getWeather(final double latitude, final double longitude) { 159 | progressBar.setVisibility(View.VISIBLE); 160 | new CurrentWeatherInfoRequest(this).sendRequest(latitude, longitude); 161 | } 162 | 163 | private void getForecastData(Location location) { 164 | if (location != null) { 165 | getForecastData(location.getLatitude(), location.getLongitude()); 166 | } 167 | } 168 | 169 | private void getForecastData(final double latitude, final double longitude) { 170 | progressBar.setVisibility(View.VISIBLE); 171 | new ForecastWeatherDataRequest(this).sendRequest(latitude, longitude); 172 | } 173 | 174 | private void getForecastData(String cityName) { 175 | progressBar.setVisibility(View.VISIBLE); 176 | new ForecastWeatherDataRequest(this).sendRequest(cityName); 177 | } 178 | 179 | private void showErrorMessage(View.OnClickListener onClickListener) { 180 | Snackbar.make(coordinatorLayout, "Something wrong!!!", Snackbar.LENGTH_LONG).setAction("Retry", onClickListener).setActionTextColor(ContextCompat.getColor(this, R.color.colorPrimary)).show(); 181 | } 182 | 183 | @Override 184 | public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { 185 | super.onRequestPermissionsResult(requestCode, permissions, grantResults); 186 | if (requestCode==LocationController.LOCATION_PERMISSION_REQUEST_CODE){ 187 | if (grantResults.length>0 && grantResults[0]==PackageManager.PERMISSION_GRANTED){ 188 | getCurrentLocation(); 189 | } 190 | } 191 | } 192 | 193 | // Subscribe On Events 194 | /////////////////////////////////////////////////////////////////////////// 195 | @SuppressWarnings("unused") 196 | @Subscribe(threadMode = ThreadMode.MAIN) 197 | public void onCurrentWeatherInfoEvent(CurrentWeatherInfoEvent currentWeatherInfoEvent) { 198 | progressBar.setVisibility(View.GONE); 199 | if (currentWeatherInfoEvent.getException() == null) { 200 | WeatherInfo weatherInfo = currentWeatherInfoEvent.getWeatherInfo(); 201 | txtHumidity.setText(weatherInfo.getHumidityUiText()); 202 | txtMinMaxTemp.setText(weatherInfo.getMinMaxTempUiText()); 203 | txtWindSpeed.setText(weatherInfo.getWindSpeedUiText()); 204 | txtCurrentTemp.setText(weatherInfo.getCurrentTempUiText()); 205 | txtCity.setText(weatherInfo.getCity()); 206 | txtDescription.setText(weatherInfo.getDescription()); 207 | VectorDrawableCompat vectorDrawableCompat = weatherIconParser.getIcon(weatherInfo.getId()); 208 | vectorDrawableCompat.setTint(ContextCompat.getColor(this, android.R.color.white)); 209 | currentWeatherIconImageView.setImageDrawable(vectorDrawableCompat); 210 | } else { 211 | showErrorMessage(new View.OnClickListener() { 212 | @Override 213 | public void onClick(View v) { 214 | if (getCurrentLocation() != null) { 215 | getWeather(getCurrentLocation()); 216 | 217 | } 218 | } 219 | }); 220 | } 221 | } 222 | 223 | @SuppressWarnings("unused") 224 | @Subscribe(threadMode = ThreadMode.MAIN) 225 | public void onForecastWeatherInfoEvent(ForecastWeatherInfoEvent forecastWeatherInfoEvent) { 226 | progressBar.setVisibility(View.GONE); 227 | if (forecastWeatherInfoEvent.getException() == null) { 228 | forecastsAdapter = new ForecastsAdapter(this, forecastWeatherInfoEvent.getWeatherInfo()); 229 | forecastsRecyclerView.setAdapter(forecastsAdapter); 230 | } else { 231 | showErrorMessage(new View.OnClickListener() { 232 | @Override 233 | public void onClick(View v) { 234 | if (getCurrentLocation() != null) { 235 | getForecastData(getCurrentLocation()); 236 | } 237 | } 238 | }); 239 | } 240 | } 241 | @SuppressWarnings("unused") 242 | @Subscribe 243 | public void onLocationChangedEvent(LocationChangedEvent locationChangedEvent) { 244 | getWeather(locationChangedEvent.getLatitude(), locationChangedEvent.getLongitude()); 245 | getForecastData(locationChangedEvent.getLatitude(), locationChangedEvent.getLongitude()); 246 | } 247 | 248 | @SuppressWarnings("unused") 249 | @Subscribe 250 | public void onCityNameChangedEvent(CityNameChanged cityNameChanged) { 251 | getWeather(cityNameChanged.getNewCityName()); 252 | getForecastData(cityNameChanged.getNewCityName()); 253 | } 254 | 255 | @SuppressWarnings("unused") 256 | @Subscribe(threadMode = ThreadMode.MAIN) 257 | public void onLocationPermissionDeniedEvent(OnLocationPermissionDeniedEvent onLocationPermissionDeniedEvent){ 258 | Snackbar.make(coordinatorLayout,OnLocationPermissionDeniedEvent.MESSAGE,Snackbar.LENGTH_LONG); 259 | } 260 | 261 | 262 | } 263 | -------------------------------------------------------------------------------- /app/src/main/java/com/sshahini/constraintsampleweather/views/dialogs/LocationChangerDialog.java: -------------------------------------------------------------------------------- 1 | package com.sshahini.constraintsampleweather.views.dialogs; 2 | 3 | import android.app.Dialog; 4 | import android.os.Bundle; 5 | import android.support.annotation.NonNull; 6 | import android.support.v4.app.DialogFragment; 7 | import android.support.v7.app.AlertDialog; 8 | import android.view.LayoutInflater; 9 | import android.view.View; 10 | import android.widget.EditText; 11 | import android.widget.TextView; 12 | 13 | import com.sshahini.constraintsampleweather.R; 14 | import com.sshahini.constraintsampleweather.events.CityNameChanged; 15 | 16 | import org.greenrobot.eventbus.EventBus; 17 | 18 | /** 19 | * Created by saeed on 7/16/16. 20 | */ 21 | public class LocationChangerDialog extends DialogFragment { 22 | @NonNull 23 | @Override 24 | public Dialog onCreateDialog(Bundle savedInstanceState) { 25 | AlertDialog.Builder builder=new AlertDialog.Builder(getActivity()); 26 | View view=LayoutInflater.from(getActivity()).inflate(R.layout.dialog_change_location,null,false); 27 | initViews(view); 28 | builder.setView(view); 29 | return builder.create(); 30 | } 31 | 32 | private void initViews(View view) { 33 | final EditText editTextCityName=(EditText)view.findViewById(R.id.location_name); 34 | final TextView btnOk=(TextView)view.findViewById(R.id.ok); 35 | final TextView btnCancel=(TextView)view.findViewById(R.id.cancel); 36 | btnOk.setOnClickListener(new View.OnClickListener() { 37 | @Override 38 | public void onClick(View v) { 39 | if (editTextCityName.getText().toString().length()>0) { 40 | dismiss(); 41 | EventBus.getDefault().post(new CityNameChanged(editTextCityName.getText().toString())); 42 | } 43 | } 44 | }); 45 | btnCancel.setOnClickListener(new View.OnClickListener() { 46 | @Override 47 | public void onClick(View v) { 48 | dismiss(); 49 | } 50 | }); 51 | } 52 | 53 | 54 | } 55 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v21/ic_add_location_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v21/ic_build_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v21/ic_clearsky.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v21/ic_cloudy.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v21/ic_edit_location_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v21/ic_fewclouds.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v21/ic_forecast.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v21/ic_home_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v21/ic_humidity_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v21/ic_info_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v21/ic_mist.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v21/ic_rain.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v21/ic_receipt_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v21/ic_replay_5_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v21/ic_shower_rain.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v21/ic_snow.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v21/ic_thunderstorm.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v21/ic_toys_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v21/ic_wallpaper_60dp.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v21/ic_wind.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_thermometer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/saeedsh92/ConstraintLayoutSample/cfd11a008cbf6c5ecb645599b53de57ea5217acb/app/src/main/res/drawable-xxxhdpi/ic_thermometer.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_thermometer_png.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/saeedsh92/ConstraintLayoutSample/cfd11a008cbf6c5ecb645599b53de57ea5217acb/app/src/main/res/drawable-xxxhdpi/ic_thermometer_png.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_wind_png.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/saeedsh92/ConstraintLayoutSample/cfd11a008cbf6c5ecb645599b53de57ea5217acb/app/src/main/res/drawable-xxxhdpi/ic_wind_png.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/img_city_downtown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/saeedsh92/ConstraintLayoutSample/cfd11a008cbf6c5ecb645599b53de57ea5217acb/app/src/main/res/drawable-xxxhdpi/img_city_downtown.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/selector_material_button.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/side_nav_bar.xml: -------------------------------------------------------------------------------- 1 | 3 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 14 | 15 | 18 | 19 | 26 | 27 | 30 | 31 | 36 | 37 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 61 | 62 | 63 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /app/src/main/res/layout/dialog_change_location.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 26 | 27 | 41 | 42 | 55 | 56 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /app/src/main/res/layout/layout_abstract_weather.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 21 | 22 | 34 | 35 | 47 | 48 | 63 | -------------------------------------------------------------------------------- /app/src/main/res/layout/layout_content_main_activity.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 15 | 16 | 21 | 22 | 26 | 27 | 37 | 38 | 50 | 51 | 52 | 64 | 65 | 75 | 76 | 86 | 87 | 99 | 100 | 101 | 102 | 103 | 108 | 109 | 121 | 122 | 133 | 134 | 135 | 142 | 143 | 144 | -------------------------------------------------------------------------------- /app/src/main/res/layout/layout_main_activity_header.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 21 | 22 | 38 | 39 | 56 | 57 | 68 | 69 | 80 | 81 | -------------------------------------------------------------------------------- /app/src/main/res/layout/layout_navigation_header.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 24 | 25 | 35 | 36 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_navigation.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 10 | 11 | 12 | 15 | 18 | 19 | 20 | 21 | 24 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/saeedsh92/ConstraintLayoutSample/cfd11a008cbf6c5ecb645599b53de57ea5217acb/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/saeedsh92/ConstraintLayoutSample/cfd11a008cbf6c5ecb645599b53de57ea5217acb/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/saeedsh92/ConstraintLayoutSample/cfd11a008cbf6c5ecb645599b53de57ea5217acb/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/saeedsh92/ConstraintLayoutSample/cfd11a008cbf6c5ecb645599b53de57ea5217acb/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/saeedsh92/ConstraintLayoutSample/cfd11a008cbf6c5ecb645599b53de57ea5217acb/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/values-v21/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 64dp 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #FF4081 6 | #aa000000 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 8dp 6 | 16dp 7 | 32dp 8 | 62dp 9 | 32dp 10 | 17sp 11 | 15sp 12 | 13sp 13 | 11sp 14 | 15 | 16dp 16 | 160dp 17 | 16dp 18 | 250dp 19 | 32dp 20 | 21 | 22 | 4dp 23 | 24 | 25 | 26 | 32dp 27 | 28 | -------------------------------------------------------------------------------- /app/src/main/res/values/drawables.xml: -------------------------------------------------------------------------------- 1 | 2 | @android:drawable/ic_menu_camera 3 | @android:drawable/ic_menu_gallery 4 | @android:drawable/ic_menu_slideshow 5 | @android:drawable/ic_menu_manage 6 | @android:drawable/ic_menu_share 7 | @android:drawable/ic_menu_send 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | WeatherS 3 | 4 | 5 | Main Screen 6 | Secondary Screen 7 | Change Location 8 | Change Picture 9 | Setting 10 | About Us 11 | 12 | Open navigation drawer 13 | Close navigation drawer 14 | 15 | Settings 16 | \u2103 17 | 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | 13 | 14 | 20 | 21 | 22 | 25 | 26 | 30 | 31 | 34 | 35 | 36 | 40 | 41 | 46 | 47 | 57 | 58 | 62 | 63 | 66 | 67 | -------------------------------------------------------------------------------- /app/src/test/java/com/sshahini/constraintsampleweather/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.sshahini.constraintsampleweather; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * To work on unit tests, switch the Box Artifact in the Build Variants view. 9 | */ 10 | public class ExampleUnitTest { 11 | @Test 12 | public void addition_isCorrect() throws Exception { 13 | assertEquals(4, 2 + 2); 14 | 15 | } 16 | } -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:2.2.0' 9 | 10 | // NOTE: Do not place your application dependencies here; they belong 11 | // in the individual module build.gradle files 12 | } 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | jcenter() 18 | } 19 | } 20 | 21 | task clean(type: Delete) { 22 | delete rootProject.buildDir 23 | } 24 | -------------------------------------------------------------------------------- /device-2016-11-19-141343.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/saeedsh92/ConstraintLayoutSample/cfd11a008cbf6c5ecb645599b53de57ea5217acb/device-2016-11-19-141343.png -------------------------------------------------------------------------------- /device-2016-11-19-141408.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/saeedsh92/ConstraintLayoutSample/cfd11a008cbf6c5ecb645599b53de57ea5217acb/device-2016-11-19-141408.png -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/saeedsh92/ConstraintLayoutSample/cfd11a008cbf6c5ecb645599b53de57ea5217acb/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Sat Sep 24 15:12:28 IRST 2016 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | --------------------------------------------------------------------------------