diff --git a/.idea/misc.xml b/.idea/misc.xml index 2a38e00..9ec28b5 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -24,10 +24,12 @@ + + diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index ecf7fee..2c6a3b6 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -10,7 +10,7 @@ android:supportsRtl="true" android:theme="@style/Theme.TimeApp"> diff --git a/app/src/main/java/com/dakotalal/timeapp/ui/HomeFragment.java b/app/src/main/java/com/dakotalal/timeapp/ui/HomeFragment.java index 7e269a1..634e030 100644 --- a/app/src/main/java/com/dakotalal/timeapp/ui/HomeFragment.java +++ b/app/src/main/java/com/dakotalal/timeapp/ui/HomeFragment.java @@ -8,6 +8,7 @@ import androidx.lifecycle.Observer; import androidx.lifecycle.ViewModelProvider; +import android.content.SharedPreferences; import android.os.Build; import android.os.Bundle; import android.util.Log; @@ -20,14 +21,17 @@ import com.dakotalal.timeapp.viewmodel.TimeViewModel; import java.time.LocalDate; +import java.time.LocalTime; import java.time.ZoneId; import java.time.ZoneOffset; +import static android.content.Context.MODE_PRIVATE; + public class HomeFragment extends Fragment { // local counts for empty timeslots private int totalEmpty, emptyToday, emptyThisWeek; - private TextView textTotalEmpty, textSpecificEmpty; + private TextView welcomeText, textTotalEmpty, textSpecificEmpty; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { @@ -45,8 +49,27 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat long weekStart = LocalDate.now().atStartOfDay(ZoneId.systemDefault()).minusDays(7).toEpochSecond(); textTotalEmpty = view.findViewById(R.id.timeslotsTotal); textSpecificEmpty = view.findViewById(R.id.timeslotsSpecific); + welcomeText = view.findViewById(R.id.welcomeMessage); + + SharedPreferences prefs = requireActivity().getSharedPreferences(MainActivity.PREFS, MODE_PRIVATE); + String name = prefs.getString(MainActivity.PREFS_NAME, ""); + String time = ""; + int hour = LocalTime.now().getHour(); + if (hour >= 6 && hour < 12) { + time = "Good morning"; + } else if (hour >= 12 && hour < 17) { + time = "Good afternoon"; + } else { + time = "Good evening"; + } + + welcomeText.setText(time + ", " + name + "!"); TimeViewModel timeViewModel = new ViewModelProvider(this).get(TimeViewModel.class); + timeViewModel.createToday(); + for (int i = 1; i < 50; i++) { + timeViewModel.createDay(LocalDate.now().minusDays(i)); + } timeViewModel.getEmptyTimeslotCountSince(0).observe(requireActivity(), count -> { totalEmpty = count; diff --git a/app/src/main/java/com/dakotalal/timeapp/ui/MainActivity.java b/app/src/main/java/com/dakotalal/timeapp/ui/MainActivity.java index a69f027..4c8bcb1 100644 --- a/app/src/main/java/com/dakotalal/timeapp/ui/MainActivity.java +++ b/app/src/main/java/com/dakotalal/timeapp/ui/MainActivity.java @@ -10,9 +10,6 @@ import com.dakotalal.timeapp.R; import com.dakotalal.timeapp.notification.Notification_Receiver; -import com.dakotalal.timeapp.ui.Statistics.SetupActivity; -import com.dakotalal.timeapp.ui.TimeActivities.TimeActivityListFragment; -import com.dakotalal.timeapp.ui.Timelog.TimelogFragment; import androidx.appcompat.app.AppCompatActivity; @@ -27,12 +24,8 @@ import com.google.android.material.navigation.NavigationBarView; import android.util.Log; -import android.view.Menu; -import android.view.MenuItem; -import android.view.View; import java.util.Calendar; -import java.util.zip.Inflater; public class MainActivity extends AppCompatActivity { diff --git a/app/src/main/java/com/dakotalal/timeapp/ui/Statistics/SetupActivity.java b/app/src/main/java/com/dakotalal/timeapp/ui/SetupActivity.java similarity index 98% rename from app/src/main/java/com/dakotalal/timeapp/ui/Statistics/SetupActivity.java rename to app/src/main/java/com/dakotalal/timeapp/ui/SetupActivity.java index fc11fd6..5bdb913 100644 --- a/app/src/main/java/com/dakotalal/timeapp/ui/Statistics/SetupActivity.java +++ b/app/src/main/java/com/dakotalal/timeapp/ui/SetupActivity.java @@ -1,4 +1,4 @@ -package com.dakotalal.timeapp.ui.Statistics; +package com.dakotalal.timeapp.ui; import androidx.appcompat.app.AppCompatActivity; diff --git a/app/src/main/java/com/dakotalal/timeapp/ui/Statistics/AllTimeStatsFragment.java b/app/src/main/java/com/dakotalal/timeapp/ui/Statistics/AllTimeStatsFragment.java new file mode 100644 index 0000000..9c70f9d --- /dev/null +++ b/app/src/main/java/com/dakotalal/timeapp/ui/Statistics/AllTimeStatsFragment.java @@ -0,0 +1,66 @@ +package com.dakotalal.timeapp.ui.Statistics; + +import android.os.Build; +import android.os.Bundle; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.RequiresApi; +import androidx.lifecycle.Observer; +import androidx.lifecycle.ViewModelProvider; +import androidx.viewpager2.widget.ViewPager2; + +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import com.dakotalal.timeapp.R; +import com.dakotalal.timeapp.room.entities.Day; +import com.dakotalal.timeapp.viewmodel.TimeViewModel; +import com.google.android.material.tabs.TabLayout; +import com.google.android.material.tabs.TabLayoutMediator; + +import java.time.DayOfWeek; +import java.time.LocalDate; +import java.time.Month; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class AllTimeStatsFragment extends IntervalStatsFragment { + ViewPager2 viewPager; + TimeViewModel viewModel; + public AllTimeStatsFragment() { + // Required empty public constructor + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + return inflater.inflate(R.layout.fragment_interval_stats, container, false); + } + + @RequiresApi(api = Build.VERSION_CODES.O) + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + viewPager = requireView().findViewById(R.id.daily_stats_view_pager); + viewPager.setAdapter(createStatsCollectionAdapter()); + viewModel = new ViewModelProvider(this).get(TimeViewModel.class); + + TabLayout tabLayout = requireView().findViewById(R.id.daily_stats_tab_layout); + tabLayout.setTabMode(TabLayout.MODE_AUTO); + new TabLayoutMediator(tabLayout, viewPager, + (tab, position) -> tab.setText(" " + (position + 1)) + ).attach(); + + // get the days and insert them into the adapter + viewModel.getAllDays().observe(requireActivity(), days -> { + List fragments = new ArrayList<>(); + fragments.add(PieStatFragment.newInstance(0, LocalDate.now().toEpochDay(), "All Time")); + adapter.setPieStatFragments(fragments); + viewPager.setCurrentItem(fragments.size()); + adapter.notifyDataSetChanged(); + }); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/dakotalal/timeapp/ui/Statistics/DailyStatsFragment.java b/app/src/main/java/com/dakotalal/timeapp/ui/Statistics/DailyStatsFragment.java new file mode 100644 index 0000000..39ad0d9 --- /dev/null +++ b/app/src/main/java/com/dakotalal/timeapp/ui/Statistics/DailyStatsFragment.java @@ -0,0 +1,103 @@ +package com.dakotalal.timeapp.ui.Statistics; + +import android.os.Build; +import android.os.Bundle; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.RequiresApi; +import androidx.lifecycle.Observer; +import androidx.lifecycle.ViewModelProvider; +import androidx.viewpager2.widget.ViewPager2; + +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import com.dakotalal.timeapp.R; +import com.dakotalal.timeapp.room.entities.Day; +import com.dakotalal.timeapp.viewmodel.TimeViewModel; +import com.google.android.material.tabs.TabLayout; +import com.google.android.material.tabs.TabLayoutMediator; + +import java.text.MessageFormat; +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.List; + +public class DailyStatsFragment extends IntervalStatsFragment { + ViewPager2 viewPager; + TimeViewModel viewModel; + public DailyStatsFragment() { + // Required empty public constructor + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + return inflater.inflate(R.layout.fragment_interval_stats, container, false); + } + + @RequiresApi(api = Build.VERSION_CODES.O) + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + viewPager = requireView().findViewById(R.id.daily_stats_view_pager); + viewPager.setAdapter(createStatsCollectionAdapter()); + viewModel = new ViewModelProvider(this).get(TimeViewModel.class); + + TabLayout tabLayout = requireView().findViewById(R.id.daily_stats_tab_layout); + tabLayout.setTabMode(TabLayout.MODE_AUTO); + new TabLayoutMediator(tabLayout, viewPager, + (tab, position) -> tab.setText(" " + (position + 1)) + ).attach(); + + // make sure today is loaded + List fragments = new ArrayList<>(); + fragments.add(PieStatFragment.newInstance(LocalDate.now().toEpochDay(), LocalDate.now().toEpochDay(), "Today")); + adapter.setPieStatFragments(fragments); + adapter.notifyDataSetChanged(); + + // get the days and insert them into the adapter + viewModel.getAllDays().observe(requireActivity(), new Observer>() { + @RequiresApi(api = Build.VERSION_CODES.O) + @Override + public void onChanged(List days) { + List fragments = new ArrayList<>(); + List labels = new ArrayList<>(); + for (Day d: days) { + LocalDate date = d.getDate(); + String label; + String dayOfWeek = date.getDayOfWeek().toString(); + String year = Integer.toString(date.getYear()); + String month = Integer.toString(date.getMonthValue()); + String monthString = date.getMonth().toString(); + String day = Integer.toString(date.getDayOfMonth()); + fragments.add(PieStatFragment.newInstance(d.getDate().toEpochDay(), d.getDate().toEpochDay(), MessageFormat.format("{0} {1} {2}, {3}", dayOfWeek, monthString, day, year))); + if (date.isAfter(LocalDate.now().minusDays(7))) { + if (date.equals(LocalDate.now())) { + label = MessageFormat.format("Today ({0}/{1}/{2})", day, month, year); + } else if (date.equals(LocalDate.now().minusDays(1))) { + label = MessageFormat.format("Yesterday ({0}/{1}/{2})", day, month, year); + } else { + label = MessageFormat.format("{0} ({1}/{2}/{3})", dayOfWeek, day, month, year); + } + } else { // show only the date for anything further than a week back + label = MessageFormat.format("{0}/{1}/{2}", day, month, year); + } + labels.add(label); + } + adapter.setPieStatFragments(fragments); + viewPager.setCurrentItem(fragments.size()); + adapter.notifyDataSetChanged(); + for (int i = 0; i < fragments.size(); i++) { + TabLayout.Tab tab = tabLayout.getTabAt(i); + if (tab != null) { + tab.setText(labels.get(i)); + } + } + + } + }); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/dakotalal/timeapp/ui/Statistics/IntervalStatsFragment.java b/app/src/main/java/com/dakotalal/timeapp/ui/Statistics/IntervalStatsFragment.java new file mode 100644 index 0000000..3a5ee2a --- /dev/null +++ b/app/src/main/java/com/dakotalal/timeapp/ui/Statistics/IntervalStatsFragment.java @@ -0,0 +1,25 @@ +package com.dakotalal.timeapp.ui.Statistics; + +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import com.dakotalal.timeapp.R; + +import androidx.fragment.app.Fragment; + +public class IntervalStatsFragment extends Fragment { + + StatsCollectionAdapter adapter; + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + return inflater.inflate(R.layout.fragment_interval_stats, container, false); + } + + public StatsCollectionAdapter createStatsCollectionAdapter() { + adapter = new StatsCollectionAdapter(getActivity()); + return adapter; + } +} diff --git a/app/src/main/java/com/dakotalal/timeapp/ui/Statistics/MonthlyStatsFragment.java b/app/src/main/java/com/dakotalal/timeapp/ui/Statistics/MonthlyStatsFragment.java new file mode 100644 index 0000000..17eb8fd --- /dev/null +++ b/app/src/main/java/com/dakotalal/timeapp/ui/Statistics/MonthlyStatsFragment.java @@ -0,0 +1,103 @@ +package com.dakotalal.timeapp.ui.Statistics; + +import android.os.Build; +import android.os.Bundle; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.RequiresApi; +import androidx.lifecycle.Observer; +import androidx.lifecycle.ViewModelProvider; +import androidx.viewpager2.widget.ViewPager2; + +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import com.dakotalal.timeapp.R; +import com.dakotalal.timeapp.room.entities.Day; +import com.dakotalal.timeapp.viewmodel.TimeViewModel; +import com.google.android.material.tabs.TabLayout; +import com.google.android.material.tabs.TabLayoutMediator; + +import java.time.DayOfWeek; +import java.time.LocalDate; +import java.time.Month; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class MonthlyStatsFragment extends IntervalStatsFragment { + ViewPager2 viewPager; + TimeViewModel viewModel; + public MonthlyStatsFragment() { + // Required empty public constructor + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + return inflater.inflate(R.layout.fragment_interval_stats, container, false); + } + + @RequiresApi(api = Build.VERSION_CODES.O) + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + viewPager = requireView().findViewById(R.id.daily_stats_view_pager); + viewPager.setAdapter(createStatsCollectionAdapter()); + viewModel = new ViewModelProvider(this).get(TimeViewModel.class); + + TabLayout tabLayout = requireView().findViewById(R.id.daily_stats_tab_layout); + tabLayout.setTabMode(TabLayout.MODE_AUTO); + new TabLayoutMediator(tabLayout, viewPager, + (tab, position) -> tab.setText(" " + (position + 1)) + ).attach(); + + // get the days and insert them into the adapter + viewModel.getAllDays().observe(requireActivity(), new Observer>() { + @RequiresApi(api = Build.VERSION_CODES.O) + @Override + public void onChanged(List days) { + List fragments = new ArrayList<>(); + List labels = new ArrayList<>(); + Day d = days.get(days.size()-1); + LocalDate date = d.getDate(); + int currentYear = LocalDate.now().getYear(); + Month currentMonth = date.getMonth(); + fragments.add(PieStatFragment.newInstance(LocalDate.of(date.getYear(), currentMonth, 1).toEpochDay(), date.toEpochDay(), currentMonth.name() + " " + date.getYear())); + labels.add(currentMonth.name()); + // create a PieStatsFragment for each month that has at least one timelog day + for (int i = days.size() - 1; i >= 0; i--) { + d = days.get(i); + date = d.getDate(); + Month month = date.getMonth(); + if (!month.equals(currentMonth)) { // if this day is from an earlier month, add all days of the month + currentMonth = month; + fragments.add(PieStatFragment.newInstance(LocalDate.of(date.getYear(), currentMonth, 1).toEpochDay(), date.toEpochDay(), currentMonth.name() + " " + date.getYear())); + String label; + if (date.getYear() == currentYear) { + label = currentMonth.name(); + } else { + label = currentMonth.name() + " " + date.getYear(); + } + labels.add(label); + } + } + + Collections.reverse(fragments); + Collections.reverse(labels); + adapter.setPieStatFragments(fragments); + viewPager.setCurrentItem(fragments.size()); + adapter.notifyDataSetChanged(); + + for (int i = 0; i < fragments.size(); i++) { + TabLayout.Tab tab = tabLayout.getTabAt(i); + if (tab != null) { + tab.setText(labels.get(i)); + } + } + } + }); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/dakotalal/timeapp/ui/Statistics/PieStatFragment.java b/app/src/main/java/com/dakotalal/timeapp/ui/Statistics/PieStatFragment.java index e5049e6..a0ff5c3 100644 --- a/app/src/main/java/com/dakotalal/timeapp/ui/Statistics/PieStatFragment.java +++ b/app/src/main/java/com/dakotalal/timeapp/ui/Statistics/PieStatFragment.java @@ -35,12 +35,6 @@ import java.util.ArrayList; import java.util.List; - -/** - * A simple {@link Fragment} subclass. - * Use the {@link PieStatFragment#newInstance} factory method to - * create an instance of this fragment. - */ public class PieStatFragment extends Fragment { private static final String ARG_TIMESTAMP_START = "timestampStart"; private static final String ARG_TIMESTAMP_END = "timestampEnd"; @@ -48,7 +42,7 @@ public class PieStatFragment extends Fragment { private long timestampStart; private long timestampEnd; - private String label; + public String label; ViewPager2 viewPager; private TimeViewModel timeViewModel; @@ -60,7 +54,8 @@ public class PieStatFragment extends Fragment { PieChart chart; List entries; - public PieStatFragment() { + public PieStatFragment(String label) { + this.label = label; // Required empty public constructor } @@ -73,7 +68,7 @@ public PieStatFragment() { * @return A new instance of fragment StatisticsFragment. */ public static PieStatFragment newInstance(long timestampStart, long timestampEnd, String label) { - PieStatFragment fragment = new PieStatFragment(); + PieStatFragment fragment = new PieStatFragment(label); Bundle args = new Bundle(); args.putLong(ARG_TIMESTAMP_START, timestampStart); args.putLong(ARG_TIMESTAMP_END, timestampEnd); @@ -135,7 +130,6 @@ public String getFormattedValue(float value, Entry entry, int dataSetIndex, View } }; - // This is a horrible approach, but I just wanted to get it working first. // TODO Improve timeslot count retrieval timeViewModel.getAllTimeActivities().observe(requireActivity(), new Observer>() { @RequiresApi(api = Build.VERSION_CODES.O) @@ -172,6 +166,7 @@ public void updateChart() { d.setValueFormatter(formatter); d.setValueTextSize(10.0f); chart.setData(d); + chart.getDescription().setEnabled(false); chart.invalidate(); } } \ No newline at end of file diff --git a/app/src/main/java/com/dakotalal/timeapp/ui/Statistics/StatsFragment.java b/app/src/main/java/com/dakotalal/timeapp/ui/Statistics/StatsFragment.java index 9908fe2..6a4caf9 100644 --- a/app/src/main/java/com/dakotalal/timeapp/ui/Statistics/StatsFragment.java +++ b/app/src/main/java/com/dakotalal/timeapp/ui/Statistics/StatsFragment.java @@ -26,7 +26,7 @@ public class StatsFragment extends BaseFragment { ViewPager2 viewPager; - StatsCollectionAdapter adapter; + StatsGroupCollectionAdapter adapter; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, @@ -38,38 +38,41 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { viewPager = requireView().findViewById(R.id.stats_view_pager); - viewPager.setAdapter(createStatsCollectionAdapter()); - + viewPager.setAdapter(createStatsGroupCollectionAdapter()); + viewPager.setUserInputEnabled(false); TabLayout tabLayout = requireView().findViewById(R.id.stats_tab_layout); tabLayout.setTabMode(TabLayout.MODE_AUTO); new TabLayoutMediator(tabLayout, viewPager, (tab, position) -> tab.setText(" " + (position + 1)) ).attach(); - List fragments = new ArrayList<>(); - fragments.add(PieStatFragment.newInstance(1L, LocalDate.now().toEpochDay(), "All Time")); - fragments.add(PieStatFragment.newInstance(LocalDate.now().minusDays(30).toEpochDay(), LocalDate.now().toEpochDay(), "Last 30 Days")); - fragments.add(PieStatFragment.newInstance(LocalDate.now().minusDays(7).toEpochDay(), LocalDate.now().toEpochDay(), "Last 7 Days")); - fragments.add(PieStatFragment.newInstance(LocalDate.now().toEpochDay(), LocalDate.now().toEpochDay(), "Today")); + List fragments = new ArrayList<>(); + fragments.add(new AllTimeStatsFragment()); + fragments.add(new MonthlyStatsFragment()); + fragments.add(new WeeklyStatsFragment()); + fragments.add(new DailyStatsFragment()); - adapter.setPieStatFragments(fragments); + adapter.setIntervalStatsFragments(fragments); adapter.notifyDataSetChanged(); // Set the tab labels to the date - for (int i = 0; i < fragments.size(); i++) { - TabLayout.Tab tab = tabLayout.getTabAt(i); - PieStatFragment fragment = fragments.get(i); - if (tab != null && fragment != null) { - Log.d("StatsFragment", "label: " + fragment.getLabel()); - tab.setText(fragment.getLabel()); - } - } - - viewPager.setCurrentItem(fragments.size()); - - adapter.notifyDataSetChanged(); +// for (int i = 0; i < fragments.size(); i++) { +// TabLayout.Tab tab = tabLayout.getTabAt(i); +// PieStatFragment fragment = fragments.get(i); +// if (tab != null && fragment != null) { +// Log.d("StatsFragment", "label: " + fragment.getLabel()); +// tab.setText(fragment.getLabel()); +// } +// } + tabLayout.getTabAt(0).setText("All"); + tabLayout.getTabAt(1).setText("Monthly"); + tabLayout.getTabAt(2).setText("Weekly"); + tabLayout.getTabAt(3).setText("Daily"); +// viewPager.setCurrentItem(fragments.size()); +// +// adapter.notifyDataSetChanged(); // showcase tutorial the first time the user opens this fragments new ShowcaseView.Builder(requireActivity()) @@ -80,8 +83,8 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat .build(); } - private StatsCollectionAdapter createStatsCollectionAdapter() { - adapter = new StatsCollectionAdapter(getActivity()); + private StatsGroupCollectionAdapter createStatsGroupCollectionAdapter() { + adapter = new StatsGroupCollectionAdapter(getActivity()); return adapter; } } \ No newline at end of file diff --git a/app/src/main/java/com/dakotalal/timeapp/ui/Statistics/StatsGroupCollectionAdapter.java b/app/src/main/java/com/dakotalal/timeapp/ui/Statistics/StatsGroupCollectionAdapter.java new file mode 100644 index 0000000..19e36ec --- /dev/null +++ b/app/src/main/java/com/dakotalal/timeapp/ui/Statistics/StatsGroupCollectionAdapter.java @@ -0,0 +1,34 @@ +package com.dakotalal.timeapp.ui.Statistics; + +import java.util.ArrayList; +import java.util.List; + +import androidx.annotation.NonNull; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentActivity; +import androidx.viewpager2.adapter.FragmentStateAdapter; + +public class StatsGroupCollectionAdapter extends FragmentStateAdapter { + + public List intervalStatsFragments; + + public StatsGroupCollectionAdapter(FragmentActivity fragmentActivity) { + super(fragmentActivity); + intervalStatsFragments = new ArrayList<>(); + } + + @NonNull + @Override + public Fragment createFragment(int position) { + return intervalStatsFragments.get(position); + } + + @Override + public int getItemCount() { + return intervalStatsFragments.size(); + } + + public void setIntervalStatsFragments(List intervalStatsFragments) { + this.intervalStatsFragments = intervalStatsFragments; + } +} diff --git a/app/src/main/java/com/dakotalal/timeapp/ui/Statistics/WeeklyStatsFragment.java b/app/src/main/java/com/dakotalal/timeapp/ui/Statistics/WeeklyStatsFragment.java new file mode 100644 index 0000000..d47d25a --- /dev/null +++ b/app/src/main/java/com/dakotalal/timeapp/ui/Statistics/WeeklyStatsFragment.java @@ -0,0 +1,88 @@ +package com.dakotalal.timeapp.ui.Statistics; + +import android.os.Build; +import android.os.Bundle; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.RequiresApi; +import androidx.lifecycle.Observer; +import androidx.lifecycle.ViewModelProvider; +import androidx.viewpager2.widget.ViewPager2; + +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import com.dakotalal.timeapp.R; +import com.dakotalal.timeapp.room.entities.Day; +import com.dakotalal.timeapp.viewmodel.TimeViewModel; +import com.google.android.material.tabs.TabLayout; +import com.google.android.material.tabs.TabLayoutMediator; + +import java.time.DayOfWeek; +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class WeeklyStatsFragment extends IntervalStatsFragment { + ViewPager2 viewPager; + TimeViewModel viewModel; + public WeeklyStatsFragment() { + // Required empty public constructor + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + return inflater.inflate(R.layout.fragment_interval_stats, container, false); + } + + @RequiresApi(api = Build.VERSION_CODES.O) + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + viewPager = requireView().findViewById(R.id.daily_stats_view_pager); + viewPager.setAdapter(createStatsCollectionAdapter()); + viewModel = new ViewModelProvider(this).get(TimeViewModel.class); + + TabLayout tabLayout = requireView().findViewById(R.id.daily_stats_tab_layout); + tabLayout.setTabMode(TabLayout.MODE_AUTO); + new TabLayoutMediator(tabLayout, viewPager, + (tab, position) -> tab.setText(" " + (position + 1)) + ).attach(); + + // get the days and insert them into the adapter + viewModel.getAllDays().observe(requireActivity(), new Observer>() { + @RequiresApi(api = Build.VERSION_CODES.O) + @Override + public void onChanged(List days) { + List fragments = new ArrayList<>(); + for (int i = days.size() - 1; i >= 0; i--) { + LocalDate lastStart = LocalDate.now(); + Day d = days.get(i); + if (d.getDate().getDayOfWeek().equals(DayOfWeek.THURSDAY)) { // if this day is the start of the week, following 6 days make up the week + lastStart = d.getDate(); + fragments.add(PieStatFragment.newInstance(d.getDate().toEpochDay(), d.getDate().plusDays(6).toEpochDay(), d.getDate().toString() + " - " + d.getDate().plusDays(6).toString())); + } else if (i == 0) { + fragments.add(PieStatFragment.newInstance(lastStart.minusDays(7).toEpochDay(), lastStart.minusDays(1).toEpochDay(), lastStart.minusDays(7).toString() + " - " + lastStart.minusDays(1).toString())); + } + } + Collections.reverse(fragments); + adapter.setPieStatFragments(fragments); + viewPager.setCurrentItem(fragments.size()); + adapter.notifyDataSetChanged(); + + for (int i = 0; i < fragments.size(); i++) { + TabLayout.Tab tab = tabLayout.getTabAt(i); + PieStatFragment fragment = fragments.get(i); + if (tab != null && fragment != null) { + tab.setText(fragment.label); + Log.d("StatsFragment", "label: " + fragment.label); + } + } + } + }); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/dakotalal/timeapp/ui/Timelog/TimelogFragment.java b/app/src/main/java/com/dakotalal/timeapp/ui/Timelog/TimelogFragment.java index 15be952..3064029 100644 --- a/app/src/main/java/com/dakotalal/timeapp/ui/Timelog/TimelogFragment.java +++ b/app/src/main/java/com/dakotalal/timeapp/ui/Timelog/TimelogFragment.java @@ -47,6 +47,8 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { timeViewModel = new ViewModelProvider(this).get(TimeViewModel.class); + // create today, so the unlogged timeslots is accurate even if the timelog hasn't been opened + timeViewModel.createToday(); viewPager = requireView().findViewById(R.id.timelog_view_pager); viewPager.setAdapter(createTimelogDayCollectionAdapter()); diff --git a/app/src/main/java/com/dakotalal/timeapp/utility/CustomViewPager.java b/app/src/main/java/com/dakotalal/timeapp/utility/CustomViewPager.java new file mode 100644 index 0000000..7ae2f2b --- /dev/null +++ b/app/src/main/java/com/dakotalal/timeapp/utility/CustomViewPager.java @@ -0,0 +1,2 @@ +package com.dakotalal.timeapp.utility;public class CustomViewPager { +} diff --git a/app/src/main/res/layout/activity_setup.xml b/app/src/main/res/layout/activity_setup.xml index 70e13b2..3736b70 100644 --- a/app/src/main/res/layout/activity_setup.xml +++ b/app/src/main/res/layout/activity_setup.xml @@ -5,7 +5,7 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/colorPrimaryLight" - tools:context=".ui.Statistics.SetupActivity"> + tools:context=".ui.SetupActivity"> diff --git a/app/src/main/res/layout/fragment_interval_stats.xml b/app/src/main/res/layout/fragment_interval_stats.xml new file mode 100644 index 0000000..55957dd --- /dev/null +++ b/app/src/main/res/layout/fragment_interval_stats.xml @@ -0,0 +1,22 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_piestat.xml b/app/src/main/res/layout/fragment_piestat.xml index e88181e..0d3f95d 100644 --- a/app/src/main/res/layout/fragment_piestat.xml +++ b/app/src/main/res/layout/fragment_piestat.xml @@ -18,6 +18,16 @@ android:textAlignment="center" android:textSize="15sp"/> + + + 30 minutes 60 minutes Your timeslot length is how much time each timeslot represents. Shorter intervals will result in a more detailed model, but will be more effort to log. -

A timeslot length of 60 minutes (24 timeslots per day) means you can log one activity every hour, whereas 15 minutes (96 timeslots per day) means you can log four activities per hour. 30 minutes is a good compromise. -

You cannot change this after you select one.
+

A timeslot length of 60 minutes (24 timeslots per day) means you can log one activity every hour, whereas 15 minutes (96 timeslots per day) means you can log four activities per hour. 30 minutes is a good compromise. +

You cannot change this after you select one.
Continue Name Comment Additional info Select Activity Done + Activities By Hour \ No newline at end of file