package org.marcinzelent.liberavem; import android.content.Context; import android.net.Uri; import android.os.Bundle; import android.support.v4.app.Fragment; import android.text.Html; import android.text.Spanned; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import org.jetbrains.annotations.Nullable; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; /** * A simple {@link Fragment} subclass. * Activities that contain this fragment must implement the * {@link AboutFragment.OnFragmentInteractionListener} interface * to handle interaction events. * Use the {@link AboutFragment#newInstance} factory method to * create an instance of this fragment. */ public class AboutFragment extends Fragment { // TODO: Rename parameter arguments, choose names that match // the fragment initialization parameters, e.g. ARG_ITEM_NUMBER private static final String ARG_PARAM1 = "param1"; private static final String ARG_PARAM2 = "param2"; // TODO: Rename and change types of parameters private String mParam1; private String mParam2; private OnFragmentInteractionListener mListener; public AboutFragment() { // Required empty public constructor } /** * Use this factory method to create a new instance of * this fragment using the provided parameters. * * @param param1 Parameter 1. * @param param2 Parameter 2. * @return A new instance of fragment AboutFragment. */ // TODO: Rename and change types and number of parameters public static AboutFragment newInstance(String param1, String param2) { AboutFragment fragment = new AboutFragment(); Bundle args = new Bundle(); args.putString(ARG_PARAM1, param1); args.putString(ARG_PARAM2, param2); fragment.setArguments(args); return fragment; } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (getArguments() != null) { mParam1 = getArguments().getString(ARG_PARAM1); mParam2 = getArguments().getString(ARG_PARAM2); } ((MainActivity) getActivity()).setActionBarTitle("About"); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Inflate the layout for this fragment return inflater.inflate(R.layout.fragment_about, container, false); } @Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { InputStream inputStream = this.getResources().openRawResource(R.raw.gpl_3); InputStreamReader inputreader = new InputStreamReader(inputStream); BufferedReader buffreader = new BufferedReader(inputreader); String line; StringBuilder text = new StringBuilder(); try { while (( line = buffreader.readLine()) != null) { text.append(line); text.append('\n'); } } catch (IOException e) { } Spanned license = Html.fromHtml(text.toString()); TextView aboutLicense = view.findViewById(R.id.about_license); aboutLicense.setText(license); } // TODO: Rename method, update argument and hook method into UI event public void onButtonPressed(Uri uri) { if (mListener != null) { mListener.onFragmentInteraction(uri); } } @Override public void onAttach(Context context) { super.onAttach(context); if (context instanceof OnFragmentInteractionListener) { mListener = (OnFragmentInteractionListener) context; } else { throw new RuntimeException(context.toString() + " must implement OnFragmentInteractionListener"); } } @Override public void onDetach() { super.onDetach(); mListener = null; } /** * This interface must be implemented by activities that contain this * fragment to allow an interaction in this fragment to be communicated * to the activity and potentially other fragments contained in that * activity. *

* See the Android Training lesson Communicating with Other Fragments for more information. */ public interface OnFragmentInteractionListener { // TODO: Update argument type and name void onFragmentInteraction(Uri uri); } } X-Content-Type-Options: nosniff Content-Security-Policy: default-src 'none' Content-Type: text/plain; charset=UTF-8 Content-Length: 3067 Content-Disposition: inline; filename="AllObservationsFragment.java" Last-Modified: Sun, 02 Feb 2025 17:24:05 GMT Expires: Sun, 02 Feb 2025 17:29:05 GMT ETag: "b54227c6f78e96da77a2504b18157837e24ad77b" package org.marcinzelent.liberavem; import android.content.Intent; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.widget.SwipeRefreshLayout; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.ListView; import android.widget.Toast; import com.android.volley.Request; import com.android.volley.RequestQueue; import com.android.volley.Response; import com.android.volley.VolleyError; import com.android.volley.toolbox.StringRequest; import com.android.volley.toolbox.Volley; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import org.jetbrains.annotations.Nullable; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Locale; import java.util.TimeZone; /** * A simple {@link Fragment} subclass. */ public class AllObservationsFragment extends Fragment { public AllObservationsFragment() { // Required empty public constructor } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.observations_list, container, false); return rootView; } @Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { final SwipeRefreshLayout sfl = view.findViewById(R.id.swiperefresh); sfl.setOnRefreshListener( new SwipeRefreshLayout.OnRefreshListener() { @Override public void onRefresh() { DataKeeper.getInstance().downloadData(getActivity()); sfl.setRefreshing(false); } } ); DataKeeper.getInstance().addFragment(this); DataKeeper.getInstance().downloadData(getActivity()); } public void populateList(final Observation[] observations, final Bird[] birds) { final ListView observationsListView = getView().findViewById(R.id.observations_list_view); observationsListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView arg0, View arg1, int position, long arg3) { Intent detailsIntent = new Intent(getActivity(), ObservationDetailsActivity.class); detailsIntent.putExtra("Observation", observations[position]); String photoUrl = ""; for (Bird bird : birds) if (bird.getId() == observations[position].getBirdId()) photoUrl = bird.getPhotoUrl(); detailsIntent.putExtra("Photo", photoUrl); startActivity(detailsIntent); } }); final ObservationsListAdapter adapter = new ObservationsListAdapter(getActivity(), observations, birds); observationsListView.setAdapter(adapter); } } X-Content-Type-Options: nosniff Content-Security-Policy: default-src 'none' Content-Type: text/plain; charset=UTF-8 Content-Length: 3000 Content-Disposition: inline; filename="AppCompatPreferenceActivity.java" Last-Modified: Sun, 02 Feb 2025 17:24:05 GMT Expires: Sun, 02 Feb 2025 17:29:05 GMT ETag: "f63b0b5b1faed8476f19a0b10c615a081b107db0" package org.marcinzelent.liberavem; import android.content.res.Configuration; import android.os.Bundle; import android.preference.PreferenceActivity; import android.support.annotation.LayoutRes; import android.support.annotation.Nullable; import android.support.v7.app.ActionBar; import android.support.v7.app.AppCompatDelegate; import android.support.v7.widget.Toolbar; import android.view.MenuInflater; import android.view.View; import android.view.ViewGroup; /** * A {@link android.preference.PreferenceActivity} which implements and proxies the necessary calls * to be used with AppCompat. */ public abstract class AppCompatPreferenceActivity extends PreferenceActivity { private AppCompatDelegate mDelegate; @Override protected void onCreate(Bundle savedInstanceState) { getDelegate().installViewFactory(); getDelegate().onCreate(savedInstanceState); super.onCreate(savedInstanceState); } @Override protected void onPostCreate(Bundle savedInstanceState) { super.onPostCreate(savedInstanceState); getDelegate().onPostCreate(savedInstanceState); } public ActionBar getSupportActionBar() { return getDelegate().getSupportActionBar(); } public void setSupportActionBar(@Nullable Toolbar toolbar) { getDelegate().setSupportActionBar(toolbar); } @Override public MenuInflater getMenuInflater() { return getDelegate().getMenuInflater(); } @Override public void setContentView(@LayoutRes int layoutResID) { getDelegate().setContentView(layoutResID); } @Override public void setContentView(View view) { getDelegate().setContentView(view); } @Override public void setContentView(View view, ViewGroup.LayoutParams params) { getDelegate().setContentView(view, params); } @Override public void addContentView(View view, ViewGroup.LayoutParams params) { getDelegate().addContentView(view, params); } @Override protected void onPostResume() { super.onPostResume(); getDelegate().onPostResume(); } @Override protected void onTitleChanged(CharSequence title, int color) { super.onTitleChanged(title, color); getDelegate().setTitle(title); } @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); getDelegate().onConfigurationChanged(newConfig); } @Override protected void onStop() { super.onStop(); getDelegate().onStop(); } @Override protected void onDestroy() { super.onDestroy(); getDelegate().onDestroy(); } public void invalidateOptionsMenu() { getDelegate().invalidateOptionsMenu(); } private AppCompatDelegate getDelegate() { if (mDelegate == null) { mDelegate = AppCompatDelegate.create(this, null); } return mDelegate; } } X-Content-Type-Options: nosniff Content-Security-Policy: default-src 'none' Content-Type: text/plain; charset=UTF-8 Content-Length: 4041 Content-Disposition: inline; filename="AtlasFragment.java" Last-Modified: Sun, 02 Feb 2025 17:24:05 GMT Expires: Sun, 02 Feb 2025 17:29:05 GMT ETag: "f59ff6bec351a4e7ab0f818ade1299ec38fdf90c" package org.marcinzelent.liberavem; import android.content.Context; import android.net.Uri; import android.os.Bundle; import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.GridView; import org.jetbrains.annotations.Nullable; /** * A simple {@link Fragment} subclass. * Activities that contain this fragment must implement the * {@link AtlasFragment.OnFragmentInteractionListener} interface * to handle interaction events. * Use the {@link AtlasFragment#newInstance} factory method to * create an instance of this fragment. */ public class AtlasFragment extends Fragment { // TODO: Rename parameter arguments, choose names that match // the fragment initialization parameters, e.g. ARG_ITEM_NUMBER private static final String ARG_PARAM1 = "param1"; private static final String ARG_PARAM2 = "param2"; // TODO: Rename and change types of parameters private String mParam1; private String mParam2; private OnFragmentInteractionListener mListener; public AtlasFragment() { // Required empty public constructor } /** * Use this factory method to create a new instance of * this fragment using the provided parameters. * * @param param1 Parameter 1. * @param param2 Parameter 2. * @return A new instance of fragment AtlasFragment. */ // TODO: Rename and change types and number of parameters public static AtlasFragment newInstance(String param1, String param2) { AtlasFragment fragment = new AtlasFragment(); Bundle args = new Bundle(); args.putString(ARG_PARAM1, param1); args.putString(ARG_PARAM2, param2); fragment.setArguments(args); return fragment; } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (getArguments() != null) { mParam1 = getArguments().getString(ARG_PARAM1); mParam2 = getArguments().getString(ARG_PARAM2); } ((MainActivity) getActivity()).setActionBarTitle("Atlas"); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Inflate the layout for this fragment return inflater.inflate(R.layout.fragment_atlas, container, false); } // TODO: Rename method, update argument and hook method into UI event public void onButtonPressed(Uri uri) { if (mListener != null) { mListener.onFragmentInteraction(uri); } } @Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { GridView atlasGrid = view.findViewById(R.id.atlas_grid); atlasGrid.setAdapter(new AtlasGridAdapter(getActivity(), DataKeeper.getInstance().getBirds())); } @Override public void onAttach(Context context) { super.onAttach(context); if (context instanceof OnFragmentInteractionListener) { mListener = (OnFragmentInteractionListener) context; } else { throw new RuntimeException(context.toString() + " must implement OnFragmentInteractionListener"); } } @Override public void onDetach() { super.onDetach(); mListener = null; } /** * This interface must be implemented by activities that contain this * fragment to allow an interaction in this fragment to be communicated * to the activity and potentially other fragments contained in that * activity. *

* See the Android Training lesson Communicating with Other Fragments for more information. */ public interface OnFragmentInteractionListener { // TODO: Update argument type and name void onFragmentInteraction(Uri uri); } } X-Content-Type-Options: nosniff Content-Security-Policy: default-src 'none' Content-Type: text/plain; charset=UTF-8 Content-Length: 1825 Content-Disposition: inline; filename="AtlasGridAdapter.java" Last-Modified: Sun, 02 Feb 2025 17:24:05 GMT Expires: Sun, 02 Feb 2025 17:29:05 GMT ETag: "0aa1ca5c7b27d6e1349ceab4646c6df59905618a" package org.marcinzelent.liberavem; import android.content.Context; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.ImageView; import android.widget.TextView; import com.squareup.picasso.Picasso; public class AtlasGridAdapter extends BaseAdapter { private Context mContext; private Bird[] birds; public AtlasGridAdapter(Context c, Bird[] b) { mContext = c; birds = b; } public int getCount() { return birds.length; } public Object getItem(int position) { return null; } public long getItemId(int position) { return 0; } // create a new ImageView for each item referenced by the Adapter public View getView(int position, View convertView, ViewGroup parent) { ViewHolder viewHolder; final View result; if (convertView == null) { viewHolder = new ViewHolder(); LayoutInflater inflater = LayoutInflater.from(mContext); convertView = inflater.inflate(R.layout.atlas_grid_item, parent, false); viewHolder.photo = convertView.findViewById(R.id.atlas_photo); viewHolder.name = convertView.findViewById(R.id.atlas_name); result = convertView; convertView.setTag(viewHolder); } else { viewHolder = (ViewHolder) convertView.getTag(); result = convertView; } Picasso.get().load(birds[position].getPhotoUrl()).into(viewHolder.photo); viewHolder.name.setText(birds[position].getNameEnglish()); return convertView; } private static class ViewHolder { ImageView photo; TextView name; } } X-Content-Type-Options: nosniff Content-Security-Policy: default-src 'none' Content-Type: text/plain; charset=UTF-8 Content-Length: 1142 Content-Disposition: inline; filename="Bird.java" Last-Modified: Sun, 02 Feb 2025 17:24:05 GMT Expires: Sun, 02 Feb 2025 17:29:05 GMT ETag: "a94faf32f97ec8043572ec9c5c520f00b8165ca9" package org.marcinzelent.liberavem; import com.google.gson.annotations.SerializedName; import java.io.Serializable; public class Bird implements Serializable { @SerializedName("Id") private int id; @SerializedName("Created") private String created; @SerializedName("NameEnglish") private String nameEnglish; @SerializedName("NameDanish") private String nameDanish; @SerializedName("PhotoUrl") private String photoUrl; public Bird(int id, String created, String nameEnglish, String nameDanish, String photoUrl) { this.id = id; this.created = created; this.nameEnglish = nameEnglish; this.nameDanish = nameDanish; this.photoUrl = photoUrl; } public int getId() { return id; } public String getCreated() { return created; } public String getNameEnglish() { return nameEnglish; } public String getNameDanish() { return nameDanish; } public String getPhotoUrl() { return photoUrl; } @Override public String toString() { return getNameEnglish(); } } X-Content-Type-Options: nosniff Content-Security-Policy: default-src 'none' Content-Type: text/plain; charset=UTF-8 Content-Length: 352 Content-Disposition: inline; filename="BirdPickerActivity.java" Last-Modified: Sun, 02 Feb 2025 17:24:05 GMT Expires: Sun, 02 Feb 2025 17:29:05 GMT ETag: "15c38cf8685cfe9707e17860a3616361ac6065c3" package org.marcinzelent.liberavem; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; public class BirdPickerActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_bird_picker); } } X-Content-Type-Options: nosniff Content-Security-Policy: default-src 'none' Content-Type: text/plain; charset=UTF-8 Content-Length: 1929 Content-Disposition: inline; filename="BirdsListAdapter.java" Last-Modified: Sun, 02 Feb 2025 17:24:05 GMT Expires: Sun, 02 Feb 2025 17:29:05 GMT ETag: "68896c00a6f2d645e9b5a5cd9a291597cdc413da" package org.marcinzelent.liberavem; import android.content.Context; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.ImageView; import android.widget.TextView; import com.squareup.picasso.Picasso; public class BirdsListAdapter extends ArrayAdapter { private final Bird[] birds; private Context mContext; public BirdsListAdapter(Context context, Bird[] birds){ super(context, R.layout.observations_list_item); this.mContext = context; this.birds = birds; } @Override public View getDropDownView(int position, @Nullable View convertView, @NonNull ViewGroup parent) { return getView(position, convertView, parent); } @Override public int getCount() { return birds.length; } @NonNull @Override public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) { ViewHolder mViewHolder = new ViewHolder(); if (convertView == null) { LayoutInflater mInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); convertView = mInflater.inflate(R.layout.birds_list_item, parent, false); mViewHolder.name = convertView.findViewById(R.id.bli_name); mViewHolder.photo = convertView.findViewById(R.id.bli_photo); convertView.setTag(mViewHolder); } else { mViewHolder = (ViewHolder) convertView.getTag(); } mViewHolder.name.setText(birds[position].getNameEnglish()); Picasso.get().load(birds[position].getPhotoUrl()).into(mViewHolder.photo); return convertView; } private static class ViewHolder { TextView name; ImageView photo; } }X-Content-Type-Options: nosniff Content-Security-Policy: default-src 'none' Content-Type: text/plain; charset=UTF-8 Content-Length: 4749 Content-Disposition: inline; filename="DataKeeper.java" Last-Modified: Sun, 02 Feb 2025 17:24:05 GMT Expires: Sun, 02 Feb 2025 17:29:05 GMT ETag: "172713d8a244e5f14383beaa9c2e87e45a034b85" package org.marcinzelent.liberavem; import android.app.Activity; import android.app.Fragment; import android.widget.Toast; import com.android.volley.Request; import com.android.volley.Response; import com.android.volley.VolleyError; import com.android.volley.toolbox.StringRequest; import com.android.volley.toolbox.Volley; import com.google.firebase.auth.FirebaseAuth; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Locale; public class DataKeeper { private static final DataKeeper instance = new DataKeeper(); public static DataKeeper getInstance() { return instance; } private DataKeeper() { } private List fragments = new ArrayList(); private Bird[] birds; private Observation[] observations; public Bird[] getBirds() { return birds; } public void setBirds(Bird[] birds) { this.birds = birds; } public Observation[] getObservations() { return observations; } public void setObservations(Observation[] observations) { this.observations = observations; } public void downloadData(final Activity activity) { if (birds == null) downloadBirds(activity); downloadObservations(activity); } private void downloadBirds(final Activity activity) { String birdsUrl = "http://birdobservationservice.azurewebsites.net/Service1.svc/birds"; final StringRequest birdsRequest = new StringRequest(Request.Method.GET, birdsUrl, new Response.Listener() { @Override public void onResponse(String response) { Gson gson = new GsonBuilder().create(); birds = gson.fromJson(response, Bird[].class); callPopulator(activity); } }, new com.android.volley.Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { Toast.makeText(activity, "Couldn't connect to the database!", Toast.LENGTH_LONG).show(); } }); Volley.newRequestQueue(activity).add(birdsRequest); } private void downloadObservations(final Activity activity) { String observationsUrl = "http://birdobservationservice.azurewebsites.net/Service1.svc/observations"; final StringRequest observationsRequest = new StringRequest(Request.Method.GET, observationsUrl, new Response.Listener() { @Override public void onResponse(String response) { Gson gson = new GsonBuilder().create(); observations = gson.fromJson(response, Observation[].class); for (Observation o : observations) { int p = o.getCreated().indexOf('+'); long epoch = Long.parseLong(o.getCreated().substring(6, p)); Date date = new Date(epoch); String formatted = new SimpleDateFormat("dd.MM.yyyy HH:mm", Locale.ENGLISH).format(date); o.setCreated(formatted); } callPopulator(activity); } }, new com.android.volley.Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { Toast.makeText(activity, "Couldn't connect to the database!", Toast.LENGTH_LONG).show(); } }); Volley.newRequestQueue(activity).add(observationsRequest); } public void addFragment(Object fragment) { fragments.add(fragment); } public void clearFragments() { fragments.clear(); } private void callPopulator(Activity activity) { if (birds != null && observations != null) { for(Object fragment : fragments) { if (fragment.getClass() == AllObservationsFragment.class) ((AllObservationsFragment) fragment).populateList(observations, birds); else { List myObservationsList = new ArrayList<>(); for (Observation o : observations) { String uid = FirebaseAuth.getInstance().getCurrentUser().getUid(); if (o.getUserId().equals(uid)) myObservationsList.add(o); } Observation[] myObservations = new Observation[myObservationsList.size()]; myObservations = myObservationsList.toArray(myObservations); ((MyObservationsFragment) fragment).populateList(myObservations, birds); } } } } } X-Content-Type-Options: nosniff Content-Security-Policy: default-src 'none' Content-Type: text/plain; charset=UTF-8 Content-Length: 4444 Content-Disposition: inline; filename="LoginActivity.java" Last-Modified: Sun, 02 Feb 2025 17:24:05 GMT Expires: Sun, 02 Feb 2025 17:29:05 GMT ETag: "354e786c8d44c30abf66354381eafc8337022c91" package org.marcinzelent.liberavem; import android.content.Intent; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; import android.text.TextUtils; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.ProgressBar; import android.widget.Toast; import com.google.android.gms.tasks.OnCompleteListener; import com.google.android.gms.tasks.Task; import com.google.firebase.auth.AuthResult; import com.google.firebase.auth.FirebaseAuth; public class LoginActivity extends AppCompatActivity { private EditText inputEmail, inputPassword; private FirebaseAuth auth; private ProgressBar progressBar; private Button btnSignup, btnLogin, btnReset; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //Get Firebase auth instance auth = FirebaseAuth.getInstance(); if (auth.getCurrentUser() != null) { startActivity(new Intent(LoginActivity.this, MainActivity.class)); finish(); } // set the view now setContentView(R.layout.activity_login); inputEmail = findViewById(R.id.email); inputPassword = findViewById(R.id.password); progressBar = findViewById(R.id.progressBar); btnSignup = findViewById(R.id.btn_signup); btnLogin = findViewById(R.id.btn_login); btnReset = findViewById(R.id.btn_reset_password); //Get Firebase auth instance auth = FirebaseAuth.getInstance(); btnSignup.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { startActivity(new Intent(LoginActivity.this, SignupActivity.class)); } }); btnReset.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { startActivity(new Intent(LoginActivity.this, ResetPasswordActivity.class)); } }); btnLogin.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { String email = inputEmail.getText().toString(); final String password = inputPassword.getText().toString(); if (TextUtils.isEmpty(email)) { Toast.makeText(getApplicationContext(), "Enter email address!", Toast.LENGTH_SHORT).show(); return; } if (TextUtils.isEmpty(password)) { Toast.makeText(getApplicationContext(), "Enter password!", Toast.LENGTH_SHORT).show(); return; } progressBar.setVisibility(View.VISIBLE); //authenticate user auth.signInWithEmailAndPassword(email, password) .addOnCompleteListener(LoginActivity.this, new OnCompleteListener() { @Override public void onComplete(@NonNull Task task) { // If sign in fails, display a message to the user. If sign in succeeds // the auth state listener will be notified and logic to handle the // signed in user can be handled in the listener. progressBar.setVisibility(View.GONE); if (!task.isSuccessful()) { // there was an error if (password.length() < 6) { inputPassword.setError(getString(R.string.minimum_password)); } else { Toast.makeText(LoginActivity.this, getString(R.string.auth_failed), Toast.LENGTH_LONG).show(); } } else { Intent intent = new Intent(LoginActivity.this, MainActivity.class); startActivity(intent); finish(); } } }); } }); } }X-Content-Type-Options: nosniff Content-Security-Policy: default-src 'none' Content-Type: text/plain; charset=UTF-8 Content-Length: 5530 Content-Disposition: inline; filename="MainActivity.java" Last-Modified: Sun, 02 Feb 2025 17:24:05 GMT Expires: Sun, 02 Feb 2025 17:29:05 GMT ETag: "37545b6c873394c1558d3a46b9243c9e0e4e0a0b" package org.marcinzelent.liberavem; import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.design.widget.FloatingActionButton; import android.support.design.widget.Snackbar; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentTransaction; import android.support.v4.widget.SwipeRefreshLayout; import android.view.View; import android.support.design.widget.NavigationView; import android.support.v4.view.GravityCompat; import android.support.v4.widget.DrawerLayout; import android.support.v7.app.ActionBarDrawerToggle; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; import android.view.Menu; import android.view.MenuItem; import android.widget.AdapterView; import android.widget.ListView; import android.widget.Toast; import com.android.volley.Request; import com.android.volley.Response; import com.android.volley.VolleyError; import com.android.volley.toolbox.StringRequest; import com.google.firebase.auth.FirebaseAuth; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import java.util.List; public class MainActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener, ObservationsFragment.OnFragmentInteractionListener, AtlasFragment.OnFragmentInteractionListener, AboutFragment.OnFragmentInteractionListener { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Toolbar toolbar = findViewById(R.id.toolbar); setSupportActionBar(toolbar); if (savedInstanceState ==null) { Fragment fragment = null; Class fragmentClass = null; fragmentClass = ObservationsFragment.class; try { fragment = (Fragment) fragmentClass.newInstance(); } catch (Exception e) { e.printStackTrace(); } FragmentManager fragmentManager = getSupportFragmentManager(); fragmentManager.beginTransaction().replace(R.id.flContent, fragment).commit(); } DrawerLayout drawer = findViewById(R.id.drawer_layout); ActionBarDrawerToggle toggle = new ActionBarDrawerToggle( this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close); drawer.addDrawerListener(toggle); toggle.syncState(); NavigationView navigationView = findViewById(R.id.nav_view); navigationView.getMenu().getItem(0).setChecked(true); navigationView.setNavigationItemSelectedListener(this); } @Override public void onBackPressed() { DrawerLayout drawer = findViewById(R.id.drawer_layout); if (drawer.isDrawerOpen(GravityCompat.START)) { drawer.closeDrawer(GravityCompat.START); } else { super.onBackPressed(); } } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); //noinspection SimplifiableIfStatement //if (id == R.id.action_search) { // return true; //} return super.onOptionsItemSelected(item); } @SuppressWarnings("StatementWithEmptyBody") @Override public boolean onNavigationItemSelected(@NonNull MenuItem item) { // Handle navigation view item clicks here. int id = item.getItemId(); Fragment fragment = null; Class fragmentClass = null; if (id == R.id.nav_observations) { fragmentClass = ObservationsFragment.class; } else if (id == R.id.nav_atlas) { fragmentClass = AtlasFragment.class; } else if (id == R.id.nav_settings) { Intent settingsIntent = new Intent(this, SettingsActivity.class); startActivity(settingsIntent); } else if (id == R.id.nav_about) { fragmentClass = AboutFragment.class; } else if (id == R.id.nav_signout) { FirebaseAuth auth = FirebaseAuth.getInstance(); auth.signOut(); finish(); Intent intent = new Intent(this, LoginActivity.class); startActivity(intent); } if (fragmentClass != null) { try { fragment = (Fragment) fragmentClass.newInstance(); } catch (Exception e) { e.printStackTrace(); } FragmentManager fragmentManager = getSupportFragmentManager(); fragmentManager.beginTransaction().replace(R.id.flContent, fragment).commit(); } DrawerLayout drawer = findViewById(R.id.drawer_layout); drawer.closeDrawer(GravityCompat.START); return true; } @Override public void onFragmentInteraction(Uri uri) { } public void setActionBarTitle(String title) { getSupportActionBar().setTitle(title); } } X-Content-Type-Options: nosniff Content-Security-Policy: default-src 'none' Content-Type: text/plain; charset=UTF-8 Content-Length: 2589 Content-Disposition: inline; filename="MyObservationsFragment.java" Last-Modified: Sun, 02 Feb 2025 17:24:05 GMT Expires: Sun, 02 Feb 2025 17:29:05 GMT ETag: "c3656e98c51c0e42aaebd56dfe1717a0ab9fa0ad" package org.marcinzelent.liberavem; import android.content.Intent; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.widget.SwipeRefreshLayout; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.ListView; import android.widget.TextView; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; /** * A simple {@link Fragment} subclass. */ public class MyObservationsFragment extends Fragment { public MyObservationsFragment() { // Required empty public constructor } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.observations_list, container, false); return rootView; } @Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { final SwipeRefreshLayout sfl = view.findViewById(R.id.swiperefresh); sfl.setOnRefreshListener( new SwipeRefreshLayout.OnRefreshListener() { @Override public void onRefresh() { DataKeeper.getInstance().downloadData(getActivity()); sfl.setRefreshing(false); } } ); DataKeeper.getInstance().addFragment(this); } public void populateList(final Observation[] observations, final Bird[] birds) { final ListView observationsListView = getView().findViewById(R.id.observations_list_view); observationsListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView arg0, View arg1, int position, long arg3) { Intent detailsIntent = new Intent(getActivity(), ObservationDetailsActivity.class); detailsIntent.putExtra("Observation", observations[position]); String photoUrl = ""; for (Bird bird : birds) if (bird.getId() == observations[position].getBirdId()) photoUrl = bird.getPhotoUrl(); detailsIntent.putExtra("Photo", photoUrl); startActivity(detailsIntent); } }); final ObservationsListAdapter adapter = new ObservationsListAdapter(getActivity(), observations, birds); observationsListView.setAdapter(adapter); } } X-Content-Type-Options: nosniff Content-Security-Policy: default-src 'none' Content-Type: text/plain; charset=UTF-8 Content-Length: 8124 Content-Disposition: inline; filename="NewObservationActivity.java" Last-Modified: Sun, 02 Feb 2025 17:24:05 GMT Expires: Sun, 02 Feb 2025 17:29:05 GMT ETag: "b331c01fb29d20de827bb118ed8a88d0dd930140" package org.marcinzelent.liberavem; import android.Manifest; import android.content.Context; import android.content.pm.PackageManager; import android.location.Location; import android.location.LocationListener; import android.location.LocationManager; import android.os.Bundle; import android.provider.ContactsContract; import android.support.v4.app.ActivityCompat; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; import android.view.View; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.EditText; import android.widget.Spinner; import android.widget.Toast; import com.android.volley.AuthFailureError; import com.android.volley.NetworkResponse; import com.android.volley.Request; import com.android.volley.Response; import com.android.volley.VolleyError; import com.android.volley.VolleyLog; import com.android.volley.toolbox.HttpHeaderParser; import com.android.volley.toolbox.StringRequest; import com.android.volley.toolbox.Volley; import com.google.firebase.auth.FirebaseAuth; import org.json.JSONException; import org.json.JSONObject; import java.io.UnsupportedEncodingException; import java.util.Calendar; public class NewObservationActivity extends AppCompatActivity { private Bird selectedBird; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_new_observation); getSupportActionBar().setDisplayHomeAsUpEnabled(true); Button cancelButton = findViewById(R.id.new_cancel); cancelButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { finish(); } }); Button button = findViewById(R.id.new_add); button.setOnClickListener(new Button.OnClickListener() { public void onClick(View view) { postNewObservation(); } }); Spinner newBirdSpinner = findViewById(R.id.new_birds); BirdsListAdapter adapter = new BirdsListAdapter(this, DataKeeper.getInstance().getBirds()); newBirdSpinner.setAdapter(adapter); newBirdSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { @Override public void onItemSelected(AdapterView adapterView, View view, int i, long l) { selectedBird = DataKeeper.getInstance().getBirds()[i]; } @Override public void onNothingSelected(AdapterView adapterView) { } }); // Acquire a reference to the system Location Manager LocationManager locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE); // Define a listener that responds to location updates LocationListener locationListener = new LocationListener() { public void onLocationChanged(Location location) { // Called when a new location is found by the network location provider. ((EditText)findViewById(R.id.new_longitude)).setText(String.valueOf(location.getLongitude())); ((EditText)findViewById(R.id.new_latitude)).setText(String.valueOf(location.getLatitude())); } public void onStatusChanged(String provider, int status, Bundle extras) { } public void onProviderEnabled(String provider) { } public void onProviderDisabled(String provider) { } }; // Register the listener with the Location Manager to receive location updates if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { // TODO: Consider calling // ActivityCompat#requestPermissions // here to request the missing permissions, and then overriding // public void onRequestPermissionsResult(int requestCode, String[] permissions, // int[] grantResults) // to handle the case where the user grants the permission. See the documentation // for ActivityCompat#requestPermissions for more details. return; } locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locationListener); } @Override public boolean onSupportNavigateUp(){ finish(); return true; } public void postNewObservation() { try { JSONObject jsonBody = new JSONObject(); jsonBody.put("BirdId", selectedBird.getId()); jsonBody.put("Comment", ((EditText)findViewById(R.id.new_comment)).getText()); jsonBody.put("Created", "/Date(" + System.currentTimeMillis() + "+0000)/"); jsonBody.put("Id", "0"); jsonBody.put("Latitude", ((EditText)findViewById(R.id.new_latitude)).getText()); jsonBody.put("Longitude", ((EditText)findViewById(R.id.new_longitude)).getText()); jsonBody.put("Placename", ((EditText)findViewById(R.id.new_place)).getText()); jsonBody.put("Population", ((EditText)findViewById(R.id.new_population)).getText()); jsonBody.put("UserId", FirebaseAuth.getInstance().getCurrentUser().getUid()); jsonBody.put("NameDanish", selectedBird.getNameDanish()); jsonBody.put("NameEnglish", selectedBird.getNameEnglish()); final String requestBody = jsonBody.toString(); String url = "http://birdobservationservice.azurewebsites.net/Service1.svc/observations"; StringRequest request = new StringRequest(Request.Method.POST, url, new Response.Listener() { @Override public void onResponse(String response) { Toast.makeText(getBaseContext(), "Successfully added activity to the database!", Toast.LENGTH_LONG).show(); NewObservationActivity.this.finish(); DataKeeper.getInstance().downloadData(NewObservationActivity.this); } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { Toast.makeText(getBaseContext(), "Couldn't add observation to the database!", Toast.LENGTH_LONG).show(); } }) { @Override public String getBodyContentType() { return "application/json; charset=utf-8"; } @Override public byte[] getBody() { try { return requestBody == null ? null : requestBody.getBytes("utf-8"); } catch (UnsupportedEncodingException uee) { VolleyLog.wtf("Unsupported Encoding while trying to get the bytes of %s using %s", requestBody, "utf-8"); return null; } } @Override protected Response parseNetworkResponse(NetworkResponse response) { String responseString = ""; if (response != null) { responseString = String.valueOf(response.statusCode); // can get more details such as response.headers } return Response.success(responseString, HttpHeaderParser.parseCacheHeaders(response)); } }; Volley.newRequestQueue(getBaseContext()).add(request); } catch (JSONException e) { e.printStackTrace(); } } } X-Content-Type-Options: nosniff Content-Security-Policy: default-src 'none' Content-Type: text/plain; charset=UTF-8 Content-Length: 3011 Content-Disposition: inline; filename="Observation.java" Last-Modified: Sun, 02 Feb 2025 17:24:05 GMT Expires: Sun, 02 Feb 2025 17:29:05 GMT ETag: "1aca80bfbdda3a78174d0a97ce554a844ab83213" package org.marcinzelent.liberavem; import com.google.gson.annotations.SerializedName; import java.io.Serializable; public class Observation implements Serializable { @SerializedName("BirdId") private int birdId; @SerializedName("Comment") private String comment; @SerializedName("Created") private String created; @SerializedName("Id") private int id; @SerializedName("Latitude") private double latitude; @SerializedName("Longitude") private double longitude; @SerializedName("Placename") private String placeName; @SerializedName("Population") private int population; @SerializedName("UserId") private String userId; @SerializedName("NameDanish") private String nameDanish; @SerializedName("NameEnglish") private String nameEnglish; public Observation(int id, String created, double latitude, double longitude, String placeName, String comment, String userId, int birdId, String nameEnglish, String nameDanish, int population) { this.birdId = birdId; this.comment = comment; this.created = created; this.id = id; this.latitude = latitude; this.longitude = longitude; this.placeName = placeName; this.population = population; this.userId = userId; this.nameDanish = nameDanish; this.nameEnglish = nameEnglish; } public int getBirdId() { return birdId; } public void setBirdId(int birdId) { this.birdId = birdId; } public String getComment() { return comment; } public void setComment(String comment) { this.comment = comment; } public String getCreated() { return created; } public void setCreated(String created) { this.created = created; } public int getId() { return id; } public void setId(int id) { this.id = id; } public double getLatitude() { return latitude; } public void setLatitude(double latitude) { this.latitude = latitude; } public double getLongitude() { return longitude; } public void setLongitude(double longitude) { this.longitude = longitude; } public String getPlaceName() { return placeName; } public void setPlaceName(String placeName) { this.placeName = placeName; } public int getPopulation() { return population; } public void setPopulation(int population) { this.population = population; } public String getUserId() { return userId; } public void setUserId(String userId) { this.userId = userId; } public String getNameDanish() { return nameDanish; } public String getNameEnglish() { return nameEnglish; } public void setNameEnglish(String nameEnglish) { this.nameEnglish = nameEnglish; } } X-Content-Type-Options: nosniff Content-Security-Policy: default-src 'none' Content-Type: text/plain; charset=UTF-8 Content-Length: 2136 Content-Disposition: inline; filename="ObservationDetailsActivity.java" Last-Modified: Sun, 02 Feb 2025 17:24:05 GMT Expires: Sun, 02 Feb 2025 17:29:05 GMT ETag: "373fda6b4514316193b6019656c64a574829f96a" package org.marcinzelent.liberavem; import android.content.Intent; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.support.v7.widget.Toolbar; import android.widget.TextView; import com.squareup.picasso.Picasso; public class ObservationDetailsActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_observation_details); getSupportActionBar().setDisplayHomeAsUpEnabled(true); Intent intent = getIntent(); Observation observation = (Observation) intent.getSerializableExtra("Observation"); String photoUrl = (String) intent.getSerializableExtra("Photo"); SquareImageView detailsPhoto = findViewById(R.id.details_photo); Picasso.get().load(photoUrl).into(detailsPhoto); TextView detailsName = findViewById(R.id.details_name); detailsName.setText(observation.getNameEnglish()); TextView detailsCreated = findViewById(R.id.details_created); detailsCreated.setText(observation.getCreated()); TextView detailsUser = findViewById(R.id.details_user); detailsUser.setText(observation.getUserId()); TextView detailsPopulation = findViewById(R.id.details_population); detailsPopulation.setText(String.valueOf(observation.getPopulation())); TextView detailsPlacename = findViewById(R.id.details_placename); detailsPlacename.setText(observation.getPlaceName()); TextView detailsLongitude = findViewById(R.id.details_longitude); detailsLongitude.setText(String.valueOf(observation.getLongitude())); TextView detailsLatitude = findViewById(R.id.details_latitude); detailsLatitude.setText(String.valueOf(observation.getLatitude())); TextView detailsComment = findViewById(R.id.details_comment); if(observation.getComment() != null) detailsComment.setText(observation.getComment()); } @Override public boolean onSupportNavigateUp(){ finish(); return true; } } X-Content-Type-Options: nosniff Content-Security-Policy: default-src 'none' Content-Type: text/plain; charset=UTF-8 Content-Length: 5115 Content-Disposition: inline; filename="ObservationsFragment.java" Last-Modified: Sun, 02 Feb 2025 17:24:05 GMT Expires: Sun, 02 Feb 2025 17:29:05 GMT ETag: "02e55125d9143ec90419e30382a0b92245e17822" package org.marcinzelent.liberavem; import android.content.Context; import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.design.widget.FloatingActionButton; import android.support.design.widget.Snackbar; import android.support.design.widget.TabLayout; import android.support.v4.app.Fragment; import android.support.v4.view.ViewPager; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; /** * A simple {@link Fragment} subclass. * Activities that contain this fragment must implement the * {@link ObservationsFragment.OnFragmentInteractionListener} interface * to handle interaction events. * Use the {@link ObservationsFragment#newInstance} factory method to * create an instance of this fragment. */ public class ObservationsFragment extends Fragment { // TODO: Rename parameter arguments, choose names that match // the fragment initialization parameters, e.g. ARG_ITEM_NUMBER private static final String ARG_PARAM1 = "param1"; private static final String ARG_PARAM2 = "param2"; // TODO: Rename and change types of parameters private String mParam1; private String mParam2; private OnFragmentInteractionListener mListener; public ObservationsFragment() { // Required empty public constructor } /** * Use this factory method to create a new instance of * this fragment using the provided parameters. * * @param param1 Parameter 1. * @param param2 Parameter 2. * @return A new instance of fragment ObservationsFragment. */ // TODO: Rename and change types and number of parameters public static ObservationsFragment newInstance(String param1, String param2) { ObservationsFragment fragment = new ObservationsFragment(); Bundle args = new Bundle(); args.putString(ARG_PARAM1, param1); args.putString(ARG_PARAM2, param2); fragment.setArguments(args); return fragment; } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (getArguments() != null) { mParam1 = getArguments().getString(ARG_PARAM1); mParam2 = getArguments().getString(ARG_PARAM2); } ((MainActivity) getActivity()).setActionBarTitle("Observations"); DataKeeper.getInstance().clearFragments(); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Inflate the layout for this fragment return inflater.inflate(R.layout.fragment_observations, container, false); } // TODO: Rename method, update argument and hook method into UI event public void onButtonPressed(Uri uri) { if (mListener != null) { mListener.onFragmentInteraction(uri); } } @Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { // Find the view pager that will allow the user to swipe between fragments ViewPager viewPager = view.findViewById(R.id.viewpager); // Create an adapter that knows which fragment should be shown on each page ViewPagerAdapter adapter = new ViewPagerAdapter(getContext(), getChildFragmentManager()); // Set the adapter onto the view pager viewPager.setAdapter(adapter); // Give the TabLayout the ViewPager TabLayout tabLayout = view.findViewById(R.id.sliding_tabs); tabLayout.setupWithViewPager(viewPager); FloatingActionButton fab = view.findViewById(R.id.fab); fab.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Intent intent = new Intent(getActivity(), NewObservationActivity.class); startActivity(intent); } }); } @Override public void onAttach(Context context) { super.onAttach(context); if (context instanceof OnFragmentInteractionListener) { mListener = (OnFragmentInteractionListener) context; } else { throw new RuntimeException(context.toString() + " must implement OnFragmentInteractionListener"); } } @Override public void onDetach() { super.onDetach(); mListener = null; } /** * This interface must be implemented by activities that contain this * fragment to allow an interaction in this fragment to be communicated * to the activity and potentially other fragments contained in that * activity. *

* See the Android Training lesson Communicating with Other Fragments for more information. */ public interface OnFragmentInteractionListener { // TODO: Update argument type and name void onFragmentInteraction(Uri uri); } } X-Content-Type-Options: nosniff Content-Security-Policy: default-src 'none' Content-Type: text/plain; charset=UTF-8 Content-Length: 2441 Content-Disposition: inline; filename="ObservationsListAdapter.java" Last-Modified: Sun, 02 Feb 2025 17:24:05 GMT Expires: Sun, 02 Feb 2025 17:29:05 GMT ETag: "b28e1628cfe8d15f3f839a7ded90d51397bad77a" package org.marcinzelent.liberavem; import android.content.Context; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.ImageView; import android.widget.TextView; import com.squareup.picasso.Picasso; public class ObservationsListAdapter extends BaseAdapter { private Context context; private final Observation[] observations; private final Bird[] birds; public ObservationsListAdapter(Context context, Observation[] observations, Bird[] birds){ //super(context, R.layout.single_list_app_item, utilsArrayList); this.context = context; this.observations = observations; this.birds = birds; } @Override public int getCount() { return observations.length; } @Override public Object getItem(int i) { return i; } @Override public long getItemId(int i) { return i; } @NonNull @Override public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) { ViewHolder viewHolder; final View result; if (convertView == null) { viewHolder = new ViewHolder(); LayoutInflater inflater = LayoutInflater.from(context); convertView = inflater.inflate(R.layout.observations_list_item, parent, false); viewHolder.name = convertView.findViewById(R.id.oli_name); viewHolder.date = convertView.findViewById(R.id.oli_date); viewHolder.photo = convertView.findViewById(R.id.oli_photo); result = convertView; convertView.setTag(viewHolder); } else { viewHolder = (ViewHolder) convertView.getTag(); result = convertView; } viewHolder.name.setText(observations[position].getNameEnglish()); viewHolder.date.setText(observations[position].getCreated()); String photoUrl = ""; for (Bird bird : birds) if (bird.getId() == observations[position].getBirdId()) photoUrl = bird.getPhotoUrl(); Picasso.get().load(photoUrl).into(viewHolder.photo); return convertView; } private static class ViewHolder { TextView name; TextView date; ImageView photo; } }X-Content-Type-Options: nosniff Content-Security-Policy: default-src 'none' Content-Type: text/plain; charset=UTF-8 Content-Length: 2610 Content-Disposition: inline; filename="ResetPasswordActivity.java" Last-Modified: Sun, 02 Feb 2025 17:24:05 GMT Expires: Sun, 02 Feb 2025 17:29:05 GMT ETag: "225730e4ec0b7866311351f541006327b0c5f3c0" package org.marcinzelent.liberavem; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.v7.app.AppCompatActivity; import android.text.TextUtils; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.ProgressBar; import android.widget.Toast; import com.google.android.gms.tasks.OnCompleteListener; import com.google.android.gms.tasks.Task; import com.google.firebase.auth.FirebaseAuth; public class ResetPasswordActivity extends AppCompatActivity { private EditText inputEmail; private Button btnReset, btnBack; private FirebaseAuth auth; private ProgressBar progressBar; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_reset_password); inputEmail = findViewById(R.id.email); btnReset = findViewById(R.id.btn_reset_password); btnBack = findViewById(R.id.btn_back); progressBar = findViewById(R.id.progressBar); auth = FirebaseAuth.getInstance(); btnBack.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { finish(); } }); btnReset.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { String email = inputEmail.getText().toString().trim(); if (TextUtils.isEmpty(email)) { Toast.makeText(getApplication(), "Enter your registered email id", Toast.LENGTH_SHORT).show(); return; } progressBar.setVisibility(View.VISIBLE); auth.sendPasswordResetEmail(email) .addOnCompleteListener(new OnCompleteListener() { @Override public void onComplete(@NonNull Task task) { if (task.isSuccessful()) { Toast.makeText(ResetPasswordActivity.this, "We have sent you instructions to reset your password!", Toast.LENGTH_SHORT).show(); } else { Toast.makeText(ResetPasswordActivity.this, "Failed to send reset email!", Toast.LENGTH_SHORT).show(); } progressBar.setVisibility(View.GONE); } }); } }); } }X-Content-Type-Options: nosniff Content-Security-Policy: default-src 'none' Content-Type: text/plain; charset=UTF-8 Content-Length: 10085 Content-Disposition: inline; filename="SettingsActivity.java" Last-Modified: Sun, 02 Feb 2025 17:24:05 GMT Expires: Sun, 02 Feb 2025 17:29:05 GMT ETag: "519ebfd0ece4fcfffc76aa29ace88ea97093bca8" package org.marcinzelent.liberavem; import android.annotation.TargetApi; import android.content.Context; import android.content.Intent; import android.content.res.Configuration; import android.media.Ringtone; import android.media.RingtoneManager; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.preference.ListPreference; import android.preference.Preference; import android.preference.PreferenceActivity; import android.support.v7.app.ActionBar; import android.preference.PreferenceFragment; import android.preference.PreferenceManager; import android.preference.RingtonePreference; import android.text.TextUtils; import android.view.MenuItem; import java.util.List; /** * A {@link PreferenceActivity} that presents a set of application settings. On * handset devices, settings are presented as a single list. On tablets, * settings are split by category, with category headers shown to the left of * the list of settings. *

* See * Android Design: Settings for design guidelines and the Settings * API Guide for more information on developing a Settings UI. */ public class SettingsActivity extends AppCompatPreferenceActivity { /** * A preference value change listener that updates the preference's summary * to reflect its new value. */ private static Preference.OnPreferenceChangeListener sBindPreferenceSummaryToValueListener = new Preference.OnPreferenceChangeListener() { @Override public boolean onPreferenceChange(Preference preference, Object value) { String stringValue = value.toString(); if (preference instanceof ListPreference) { // For list preferences, look up the correct display value in // the preference's 'entries' list. ListPreference listPreference = (ListPreference) preference; int index = listPreference.findIndexOfValue(stringValue); // Set the summary to reflect the new value. preference.setSummary( index >= 0 ? listPreference.getEntries()[index] : null); } else if (preference instanceof RingtonePreference) { // For ringtone preferences, look up the correct display value // using RingtoneManager. if (TextUtils.isEmpty(stringValue)) { // Empty values correspond to 'silent' (no ringtone). preference.setSummary(R.string.pref_ringtone_silent); } else { Ringtone ringtone = RingtoneManager.getRingtone( preference.getContext(), Uri.parse(stringValue)); if (ringtone == null) { // Clear the summary if there was a lookup error. preference.setSummary(null); } else { // Set the summary to reflect the new ringtone display // name. String name = ringtone.getTitle(preference.getContext()); preference.setSummary(name); } } } else { // For all other preferences, set the summary to the value's // simple string representation. preference.setSummary(stringValue); } return true; } }; /** * Helper method to determine if the device has an extra-large screen. For * example, 10" tablets are extra-large. */ private static boolean isXLargeTablet(Context context) { return (context.getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_XLARGE; } /** * Binds a preference's summary to its value. More specifically, when the * preference's value is changed, its summary (line of text below the * preference title) is updated to reflect the value. The summary is also * immediately updated upon calling this method. The exact display format is * dependent on the type of preference. * * @see #sBindPreferenceSummaryToValueListener */ private static void bindPreferenceSummaryToValue(Preference preference) { // Set the listener to watch for value changes. preference.setOnPreferenceChangeListener(sBindPreferenceSummaryToValueListener); // Trigger the listener immediately with the preference's // current value. sBindPreferenceSummaryToValueListener.onPreferenceChange(preference, PreferenceManager .getDefaultSharedPreferences(preference.getContext()) .getString(preference.getKey(), "")); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setupActionBar(); } /** * Set up the {@link android.app.ActionBar}, if the API is available. */ private void setupActionBar() { ActionBar actionBar = getSupportActionBar(); if (actionBar != null) { // Show the Up button in the action bar. actionBar.setDisplayHomeAsUpEnabled(true); } } /** * {@inheritDoc} */ @Override public boolean onIsMultiPane() { return isXLargeTablet(this); } /** * {@inheritDoc} */ @Override @TargetApi(Build.VERSION_CODES.HONEYCOMB) public void onBuildHeaders(List

target) { loadHeadersFromResource(R.xml.pref_headers, target); } /** * This method stops fragment injection in malicious applications. * Make sure to deny any unknown fragments here. */ protected boolean isValidFragment(String fragmentName) { return PreferenceFragment.class.getName().equals(fragmentName) || GeneralPreferenceFragment.class.getName().equals(fragmentName) || DataSyncPreferenceFragment.class.getName().equals(fragmentName) || NotificationPreferenceFragment.class.getName().equals(fragmentName); } /** * This fragment shows general preferences only. It is used when the * activity is showing a two-pane settings UI. */ @TargetApi(Build.VERSION_CODES.HONEYCOMB) public static class GeneralPreferenceFragment extends PreferenceFragment { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.pref_general); setHasOptionsMenu(true); // Bind the summaries of EditText/List/Dialog/Ringtone preferences // to their values. When their values change, their summaries are // updated to reflect the new value, per the Android Design // guidelines. bindPreferenceSummaryToValue(findPreference("example_text")); bindPreferenceSummaryToValue(findPreference("example_list")); } @Override public boolean onOptionsItemSelected(MenuItem item) { int id = item.getItemId(); if (id == android.R.id.home) { startActivity(new Intent(getActivity(), SettingsActivity.class)); return true; } return super.onOptionsItemSelected(item); } } /** * This fragment shows notification preferences only. It is used when the * activity is showing a two-pane settings UI. */ @TargetApi(Build.VERSION_CODES.HONEYCOMB) public static class NotificationPreferenceFragment extends PreferenceFragment { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.pref_notification); setHasOptionsMenu(true); // Bind the summaries of EditText/List/Dialog/Ringtone preferences // to their values. When their values change, their summaries are // updated to reflect the new value, per the Android Design // guidelines. bindPreferenceSummaryToValue(findPreference("notifications_new_message_ringtone")); } @Override public boolean onOptionsItemSelected(MenuItem item) { int id = item.getItemId(); if (id == android.R.id.home) { startActivity(new Intent(getActivity(), SettingsActivity.class)); return true; } return super.onOptionsItemSelected(item); } } /** * This fragment shows data and sync preferences only. It is used when the * activity is showing a two-pane settings UI. */ @TargetApi(Build.VERSION_CODES.HONEYCOMB) public static class DataSyncPreferenceFragment extends PreferenceFragment { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.pref_data_sync); setHasOptionsMenu(true); // Bind the summaries of EditText/List/Dialog/Ringtone preferences // to their values. When their values change, their summaries are // updated to reflect the new value, per the Android Design // guidelines. bindPreferenceSummaryToValue(findPreference("sync_frequency")); } @Override public boolean onOptionsItemSelected(MenuItem item) { int id = item.getItemId(); if (id == android.R.id.home) { startActivity(new Intent(getActivity(), SettingsActivity.class)); return true; } return super.onOptionsItemSelected(item); } } } X-Content-Type-Options: nosniff Content-Security-Policy: default-src 'none' Content-Type: text/plain; charset=UTF-8 Content-Length: 4323 Content-Disposition: inline; filename="SignupActivity.java" Last-Modified: Sun, 02 Feb 2025 17:24:05 GMT Expires: Sun, 02 Feb 2025 17:29:05 GMT ETag: "305f3bcb4b1c604f267e0b8f5e040cbb52e29f57" package org.marcinzelent.liberavem; import android.content.Intent; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.v7.app.AppCompatActivity; import android.text.TextUtils; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.ProgressBar; import android.widget.Toast; import com.google.android.gms.tasks.OnCompleteListener; import com.google.android.gms.tasks.Task; import com.google.firebase.auth.AuthResult; import com.google.firebase.auth.FirebaseAuth; public class SignupActivity extends AppCompatActivity { private EditText inputEmail, inputPassword; private Button btnSignIn, btnSignUp, btnResetPassword; private ProgressBar progressBar; private FirebaseAuth auth; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_signup); //Get Firebase auth instance auth = FirebaseAuth.getInstance(); btnSignIn = findViewById(R.id.sign_in_button); btnSignUp = findViewById(R.id.sign_up_button); inputEmail = findViewById(R.id.email); inputPassword = findViewById(R.id.password); progressBar = findViewById(R.id.progressBar); btnResetPassword = findViewById(R.id.btn_reset_password); btnResetPassword.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { startActivity(new Intent(SignupActivity.this, ResetPasswordActivity.class)); } }); btnSignIn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { finish(); } }); btnSignUp.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { String email = inputEmail.getText().toString().trim(); String password = inputPassword.getText().toString().trim(); if (TextUtils.isEmpty(email)) { Toast.makeText(getApplicationContext(), "Enter email address!", Toast.LENGTH_SHORT).show(); return; } if (TextUtils.isEmpty(password)) { Toast.makeText(getApplicationContext(), "Enter password!", Toast.LENGTH_SHORT).show(); return; } if (password.length() < 6) { Toast.makeText(getApplicationContext(), "Password too short, enter minimum 6 characters!", Toast.LENGTH_SHORT).show(); return; } progressBar.setVisibility(View.VISIBLE); //create user auth.createUserWithEmailAndPassword(email, password) .addOnCompleteListener(SignupActivity.this, new OnCompleteListener() { @Override public void onComplete(@NonNull Task task) { Toast.makeText(SignupActivity.this, "createUserWithEmail:onComplete:" + task.isSuccessful(), Toast.LENGTH_SHORT).show(); progressBar.setVisibility(View.GONE); // If sign in fails, display a message to the user. If sign in succeeds // the auth state listener will be notified and logic to handle the // signed in user can be handled in the listener. if (!task.isSuccessful()) { Toast.makeText(SignupActivity.this, "Authentication failed." + task.getException(), Toast.LENGTH_SHORT).show(); } else { startActivity(new Intent(SignupActivity.this, MainActivity.class)); finish(); } } }); } }); } @Override protected void onResume() { super.onResume(); progressBar.setVisibility(View.GONE); } } X-Content-Type-Options: nosniff Content-Security-Policy: default-src 'none' Content-Type: text/plain; charset=UTF-8 Content-Length: 744 Content-Disposition: inline; filename="SquareImageView.java" Last-Modified: Sun, 02 Feb 2025 17:24:05 GMT Expires: Sun, 02 Feb 2025 17:29:05 GMT ETag: "ed5dbb7e028d5ba80b1fc50b8ec304605d803d82" package org.marcinzelent.liberavem; import android.content.Context; import android.util.AttributeSet; public class SquareImageView extends android.support.v7.widget.AppCompatImageView { public SquareImageView(Context context) { super(context); } public SquareImageView(Context context, AttributeSet attrs) { super(context, attrs); } public SquareImageView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int width = getMeasuredWidth(); setMeasuredDimension(width, width); } } X-Content-Type-Options: nosniff Content-Security-Policy: default-src 'none' Content-Type: text/plain; charset=UTF-8 Content-Length: 1239 Content-Disposition: inline; filename="ViewPagerAdapter.java" Last-Modified: Sun, 02 Feb 2025 17:24:05 GMT Expires: Sun, 02 Feb 2025 17:29:05 GMT ETag: "8c20fc9dbe33b08e920b5f1e19eb3774ccb5fb86" package org.marcinzelent.liberavem; import android.content.Context; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentPagerAdapter; public class ViewPagerAdapter extends FragmentPagerAdapter { private Context mContext; public ViewPagerAdapter(Context context, FragmentManager fm) { super(fm); mContext = context; } // This determines the fragment for each tab @Override public Fragment getItem(int position) { if (position == 0) { return new MyObservationsFragment(); } else { return new AllObservationsFragment(); } } // This determines the number of tabs @Override public int getCount() { return 2; } // This determines the title for each tab @Override public CharSequence getPageTitle(int position) { // Generate title based on item position switch (position) { case 0: return mContext.getString(R.string.my_observations); case 1: return mContext.getString(R.string.all_observations); default: return null; } } }