Java tutorial
/** * This file is part of AviationHK - companion app for local pilots * that provides at-a-glance weather information. * <p> * Project site: https://github.com/sonny-chen/aviation-weather-android * <p> * AviationHK is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * <p> * AviationHK is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * <p> * You should have received a copy of the GNU General Public License * along with AviationHK. If not, see <http://www.gnu.org/licenses/>. * <p> * Created by Sonny Chen on 4/25/2017. **/ package com.sonnychen.aviationhk.views; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.graphics.Color; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.content.LocalBroadcastManager; import android.support.v7.widget.GridLayoutManager; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.text.Html; import android.text.TextUtils; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.LinearLayout; import android.widget.TextView; import com.sonnychen.aviationhk.BaseApplication; import com.sonnychen.aviationhk.R; import com.sonnychen.aviationhk.parsers.BasicSyncCallback.DataType; import com.sonnychen.aviationhk.parsers.HKOData; import com.sonnychen.aviationhk.parsers.HKORss; import com.sonnychen.aviationhk.utils.GenericCardItem; import com.sonnychen.aviationhk.utils.GenericRecyclerViewAdapter; import com.sonnychen.aviationhk.utils.Utils; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Locale; import static com.sonnychen.aviationhk.parsers.BasicSyncCallback.DataType.FORECASTS; import static com.sonnychen.aviationhk.parsers.BasicSyncCallback.DataType.VHSK; import static com.sonnychen.aviationhk.parsers.BasicSyncCallback.DataType.valueOf; import static com.sonnychen.aviationhk.utils.Utils.getMaxNumberOfFittedColumns; /** * A simple {@link Fragment} subclass. * Activities that contain this fragment must implement the * {@link CustomFragmentBase.OnFragmentInteractionListener} interface * to handle interaction events. * Use the {@link HomeFragment#newInstance} factory method to * create an instance of this fragment. */ public class HomeFragment extends CustomFragmentBase { public HomeFragment() { // Required empty public constructor } /** * Use this factory method to create a new instance of * this fragment using the provided parameters. */ public static HomeFragment newInstance(Context context) { HomeFragment fragment = new HomeFragment(); fragment.FragmentTitle = context.getString(R.string.title_home); return fragment; } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } // HTML parsed TextView mWind; TextView mQNH; TextView mWeather; TextView mCloudBase; TextView mVisibility; TextView mVisibilityLocal; TextView mVHSKTemperature; TextView mVHSKWind; TextView mVHSKPressure; // RSS TextView mLocalForecast; TextView mGeneralSituation; RecyclerView mExtendedForecasts; TextView mWeatherWarnings; // weather forecast ArrayList<GenericCardItem> cardList; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Inflate the layout for this fragment View view = inflater.inflate(R.layout.fragment_home, container, false); Log.v("HOME-UI", "Starting"); mQNH = ((TextView) view.findViewById(R.id.txtQNH)); mQNH.setText(BaseApplication.Data.METAR_QNH); mWeather = ((TextView) view.findViewById(R.id.txtWeather)); mWeather.setText(BaseApplication.Data.METAR_Weather); mCloudBase = ((TextView) view.findViewById(R.id.txtCloud)); if (BaseApplication.Data.METAR_Weather.startsWith("No significant")) mCloudBase.setTextColor(Color.parseColor("#006600")); mWeatherWarnings = ((TextView) view.findViewById(R.id.txtWeatherWarnings)); mWeatherWarnings.setText(Html.fromHtml(Arrays.toString(BaseApplication.RssData.WeatherWarnings))); mLocalForecast = ((TextView) view.findViewById(R.id.txtLocalForecast)); if (BaseApplication.RssData.LocalWeatherForecastDescription != null) mLocalForecast.setText(Html.fromHtml(BaseApplication.RssData.LocalWeatherForecastDescription)); mGeneralSituation = ((TextView) view.findViewById(R.id.txtLocalForecast)); if (BaseApplication.RssData.GeneralSituation != null) mLocalForecast.setText(Html.fromHtml(BaseApplication.RssData.GeneralSituation)); String[] data; // set label colors mWind = ((TextView) view.findViewById(R.id.txtWind)); if (!TextUtils.isEmpty(BaseApplication.Data.METAR_Wind)) { mWind.setText(BaseApplication.Data.METAR_Wind); data = BaseApplication.Data.METAR_Wind.split(" "); if (Utils.isInteger(data[0], 10)) { // minima: 2000 ft SEC, 1200 ft SKARA int value = Integer.parseInt(data[0]); if (value > 20) mWind.setTextColor(Color.RED); else mWind.setTextColor(Color.BLACK); } else mWind.setTextColor(Color.BLACK); } mCloudBase = ((TextView) view.findViewById(R.id.txtCloud)); if (!TextUtils.isEmpty(BaseApplication.Data.METAR_CloudBase)) { mCloudBase.setText(BaseApplication.Data.METAR_CloudBase); data = BaseApplication.Data.METAR_CloudBase.split(" "); if (Utils.isInteger(data[0], 10)) { // minima: 2000 ft SEC, 1200 ft SKARA int value = Integer.parseInt(data[0]); if (value > 2000) mCloudBase.setTextColor(Color.parseColor("#006600")); else if (value > 1200) mCloudBase.setTextColor(Color.parseColor("#e67300")); else mCloudBase.setTextColor(Color.RED); } else mCloudBase.setTextColor(Color.BLACK); } mVisibility = ((TextView) view.findViewById(R.id.txtVisibility)); if (!TextUtils.isEmpty(BaseApplication.Data.METAR_Visibility)) { mVisibility.setText(BaseApplication.Data.METAR_Visibility); data = BaseApplication.Data.METAR_Visibility.split(" "); if (Utils.isInteger(data[0], 10)) { // data format: 7 km 3000 m // minima: 5 km SKARA/SEC int value = Integer.parseInt(data[0]); if (value > 3 && value <= 10) mVisibility.setTextColor(Color.parseColor("#006600")); else if (value == 3000) mVisibility.setTextColor(Color.parseColor("#e67300")); else mVisibility.setTextColor(Color.RED); } else mVisibility.setTextColor(Color.BLACK); } mVisibilityLocal = ((TextView) view.findViewById(R.id.txtVisibilityLocal)); mVHSKTemperature = ((TextView) view.findViewById(R.id.txtVHSKTemperature)); mVHSKWind = ((TextView) view.findViewById(R.id.txtVHSKWind)); mVHSKPressure = ((TextView) view.findViewById(R.id.txtVHSKPressure)); mExtendedForecasts = ((RecyclerView) view.findViewById(R.id.extendedForecasts)); if (BaseApplication.Data.VHSK_Temperature_Celsius > 0) bindVHSKReadings(VHSK); if (BaseApplication.RssData.WeatherForecasts != null) bindVHSKReadings(FORECASTS); return view; } private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { Log.v("HomeFragment", "Broadcast received: " + intent.toString()); // wait for METAR to finish before loading UI if (intent.hasExtra(BaseApplication.SYNC_EVENT_PARAM)) bindVHSKReadings(valueOf(intent.getStringExtra(BaseApplication.SYNC_EVENT_PARAM))); } }; @Override public void onAttach(Context context) { super.onAttach(context); // register for sync event broadcasts LocalBroadcastManager.getInstance(context).registerReceiver(broadcastReceiver, new IntentFilter(BaseApplication.SYNC_EVENT)); } @Override public void onDetach() { super.onDetach(); LocalBroadcastManager.getInstance(getContext()).unregisterReceiver(broadcastReceiver); } private void bindVHSKReadings(DataType dataType) { Log.v("HomeFragment", "bindVHSKReadings: " + dataType.toString()); switch (dataType) { case FORECASTS: StringBuilder sb = new StringBuilder(); for (HKOData.Visibility visibility : BaseApplication.Data.VisibilityReadings) sb.append(String.format(Locale.ENGLISH, "%s: %.0f km\n", visibility.Location, visibility.Visibility_10min_KM)); mVisibilityLocal.setText(sb.toString()); if (BaseApplication.RssData.WeatherForecasts != null) { cardList = new ArrayList<>(); SimpleDateFormat dateFormat = new SimpleDateFormat("EEE dd/MM", Locale.ENGLISH); for (HKORss.WeatherForecast forecast : BaseApplication.RssData.WeatherForecasts) { cardList.add(new GenericCardItem(forecast.Date != null ? forecast.Date.toString() : "", forecast.WeatherCartoonURL, String.format(Locale.ENGLISH, "%s<br />%s<br /><br />%s<br />%s", forecast.Date != null ? dateFormat.format(forecast.Date) : "", forecast.Weather, forecast.TemperatureRange, forecast.Wind))); } GridLayoutManager mLayoutManager = new GridLayoutManager(getContext(), getMaxNumberOfFittedColumns(getActivity(), 100), LinearLayoutManager.VERTICAL, false); mExtendedForecasts.setLayoutManager(mLayoutManager); mLayoutManager.setAutoMeasureEnabled(true); mExtendedForecasts.setHasFixedSize(false); mExtendedForecasts.setNestedScrollingEnabled(false); mExtendedForecasts .setAdapter(new GenericRecyclerViewAdapter(getContext(), cardList, LinearLayout.VERTICAL)); } break; case VHSK: mVHSKTemperature.setText(String.format(Locale.ENGLISH, "%.1fC (%.1fC ~ %.1fC)", BaseApplication.Data.VHSK_Temperature_Celsius, BaseApplication.Data.VHSK_TemperatureMin_Celsius, BaseApplication.Data.VHSK_TemperatureMax_Celsius)); mVHSKWind.setText(String.format(Locale.ENGLISH, "%s %s - %s %s %s", BaseApplication.Data.VHSK_WindDirection, Math.round(BaseApplication.Data.VHSK_Wind_Knots) > 0 ? String.format( Locale.ENGLISH, "%d kts", Math.round(BaseApplication.Data.VHSK_Wind_Knots)) : "", getString(R.string.crosswind), Math.round(BaseApplication.Data.VHSK_CrossWind_Knots) > 0 ? String.format(Locale.ENGLISH, "%d kts", Math.round(BaseApplication.Data.VHSK_CrossWind_Knots)) : "nil", Math.round(BaseApplication.Data.VHSK_CrossWind_Knots) > 0 ? (BaseApplication.Data.VHSK_CrossWind_Angle < 0 ? "from the left of 11" : "from the right of 11") : "")); // check for weather minimas mVHSKWind.setTextColor((Math.round(BaseApplication.Data.VHSK_Wind_Knots) > 20 || Math.round(BaseApplication.Data.VHSK_CrossWind_Knots) > 15) ? Color.RED : Color.BLACK); mVHSKPressure .setText(String.format(Locale.ENGLISH, "%.0f hPa", BaseApplication.Data.VHSK_Pressure_hPa)); break; } } }